Introduzione

Questo documento fornisce un’ampia panoramica sul corso di Analisi Predittiva di Ca’ Foscari (CT0429) dell’anno 2023/2024. Nel corso del documento, esploreremo vari argomenti riguardanti l’Analisi Predittiva, compresi Anova, Residui, Formule, Correlazione tra variabili, Predict, l’utilizzo di più modelli, e come selezionare le variabili all’interno di un modello.

L’obiettivo di questo documento è guidarti attraverso i concetti chiave e le pratiche nell’Analisi Predittiva, con un focus sull’utilizzo del linguaggio di programmazione R per applicare queste tecniche. Spero che questo documento ti aiuti a comprendere meglio questa materia di studio al fine di superare l’esame.

Regressione Lineare

La Regressione Lineare (LR) è una tecnica statistica che viene utilizzata per studiare la relazione tra due o più variabili quantitative. Il modello di regressione lineare assume che la variabile dipendente, che si desidera predire, sia una funzione lineare delle variabili indipendenti.

Il modello di regressione lineare fa le seguenti assunzioni:

L’equazione del modello di regressione lineare semplice è la seguente:

\[ y = a + bx \]

dove:

L’intercetta rappresenta il valore medio di y quando x è uguale a 0. Il coefficiente angolare rappresenta la variazione di y per ogni unità di variazione di x.

Analisi dei residui

Serve a verificare se il modello soddisfa le assunzioni della regressione e per identificare eventuali pattern o problemi nei dati.

Esempio 1:

# Generiamo dati casuali con residui normalmente distribuiti
set.seed(123)
x <- 1:100
y <- 2 * x + rnorm(100)

# Adattiamo un modello di regressione
model <- lm(y ~ x)

# Effettuiamo l'analisi dei residui
Residuals <- residuals(model)

# Creiamo un grafico dei residui
plot(x, Residuals, main = "Distribuzione Normale dei Residui",xlab = "X", ylab = "Residui")
abline(h = 0, col = "red")

In questo caso, i residui seguono una distribuzione normale, il che è un risultato ideale per un modello di regressione lineare. Quando diciamo che i residui hanno una distribuzione normale, significa che i residui seguono una distribuzione a forma di campana, con una media di zero e una varianza costante. Questa è un’importante assunzione nei modelli di regressione lineare, in quanto indica che gli errori casuali nel modello sono distribuiti in modo simmetrico intorno a zero e non mostrano alcun tipo di tendenza sistemica. Se questa assunzione è soddisfatta, i test di significatività dei coefficienti del modello e le stime di intervallo di confidenza saranno affidabili.

Esempio 2:

# Generiamo dati casuali con residui che seguono una distribuzione a U
set.seed(456)
x <- 1:100
y <- 2 * x^2 + rnorm(100)
y[50:60] <- y[50:60] + 10  # Introduciamo un effetto a U nei dati

# Adattiamo un modello di regressione
model <- lm(y ~ x)

# Effettuiamo l'analisi dei residui
residuals <- residuals(model)

# Creiamo un grafico dei residui
plot(x, residuals, main = "Distribuzione a U dei Residui", xlab = "X", ylab = "Residui")
abline(h = 0, col = "red")

In questo caso, i residui mostrano un effetto a U, indicando una violazione dell’assunzione di omoschedasticità(i residui non mostrano un aumento o una diminuzione sistematica nella dispersione al variare dei valori delle variabili indipendenti).

Esempio 3:

# Generiamo dati casuali con outlier nei residui
set.seed(789)
x <- 1:100
y <- 2 * x + rnorm(100)
y[c(20, 85)] <- y[c(20, 85)] + 20  # Aggiungiamo outlier nei dati

# Adattiamo un modello di regressione
model <- lm(y ~ x)

# Effettuiamo l'analisi dei residui
residuals <- residuals(model)

# Creiamo un grafico dei residui
plot(x, residuals, main = "Presenza di Outlier nei Residui", ylab = "Residui", xlab = "X")
abline(h = 0, col = "red")

In questo caso, i residui mostrano la presenza di outlier evidenti, che possono influenzare in modo significativo la stima dei coefficienti del modello. Gli outlier possono comportare problemi nei modelli statistici, specialmente nei modelli di regressione, perché possono influenzare notevolmente i risultati. Ad esempio, possono influenzare la stima dei coefficienti del modello e rendere il modello meno affidabile.

[Torna all’ Indice]

Scomposizione Somma Di Quadrati

La “decomposition of sum of squares” è un concetto fondamentale nell’analisi della varianza (ANOVA) e nella regressione statistica. Questa tecnica aiuta a scomporre la varianza totale osservata in un insieme di dati in diverse componenti, consentendo di comprendere quanto della varianza può essere attribuito a vari fattori o errori residui. La formula chiave in questo contesto è:

\[ Varianza Totale = Varianza Spiegata + Varianza Residua \]

Dove:

  • Varianza Totale è la varianza complessiva dei dati, cioè quanto i dati variano in generale.

  • Varianza Spiegata rappresenta la varianza dovuta al modello o ai fattori esaminati (spiegati dalla variabile indipendente nel contesto della regressione).

  • Varianza Residua è la varianza non spiegata dal modello o dai fattori ed è associata all’errore residuo, ovvero la differenza tra i valori osservati e quelli previsti dal modello.

Nel contesto della regressione, puoi rappresentare la decomposizione della somma dei quadrati come segue:

\[ SST = SSR + SSE \]

  • SST (Sum of Squares Total) rappresenta la somma dei quadrati totale ed è la varianza dei dati osservati rispetto alla loro media.

  • SSR (Sum of Squares Regression) rappresenta la varianza spiegata dal modello o dalla variabile indipendente.

  • SSE (Sum of Squares Error) rappresenta la varianza residua, ossia la varianza non spiegata dal modello.

Per valutare l’efficienza del tuo modello di regressione, dovresti guardare la proporzione di questa varianza spiegata dal tuo modello (SSR). In generale, vuoi massimizzare la proporzione spiegata e minimizzare la proporzione non spiegata (SSE). Pertanto, punti a minimizzare SSE.

data <- data.frame(X = c(1, 2, 3, 4, 5), Y = c(3, 5, 6, 8, 10))
mean_Y <- mean(data$Y)
SST <- sum((data$Y - mean_Y)^2)

# Adatta il modello di regressione lineare
model <- lm(Y ~ X, data = data)

# Calcola la SSR
SSR <- sum((predict(model) - mean_Y)^2)

# Calcola la SSE
SSE <- sum(model$residuals^2)

R_squared <- SSR / SST

# Equivale a fare summary(model)
R_squared
[1] 0.989726

[Torna all’ Indice]

Predizione Ottimale

L’“Optimal Prediction” riguarda la determinazione di un modello predittivo che sia il migliore possibile in termini di accuratezza nel prevedere gli eventi futuri.

L’obiettivo principale è trovare il modello che massimizza la precisione delle previsioni, minimizzando l’errore di previsione. Ci sono vari metodi e tecniche per ottenere la predizione ottimale, a seconda del contesto e dei dati disponibili.

# Caricamento del dataset "cars"
data(cars)

# Visualizzazione delle prime righe del dataset
head(cars)

# Dividiamo il dataset in set di addestramento e set di test
set.seed(123)  # Impostiamo un seed per la riproducibilità
sample_indices <- sample(nrow(cars), nrow(cars) * 0.7)  # 70% dati di addestramento
train_data <- cars[sample_indices, ]
test_data <- cars[-sample_indices, ]

# Adattamento di un modello di regressione lineare
model <- lm(dist ~ speed, data = train_data)

# Predizioni
predictions <- predict(model, newdata = test_data)

# Valutazione delle prestazioni
summary(model)

Call:
lm(formula = dist ~ speed, data = train_data)

Residuals:
    Min      1Q  Median      3Q     Max 
-18.820  -8.798  -2.272   5.614  44.951 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) -22.0481     7.4169  -2.973  0.00548 ** 
speed         4.0457     0.4589   8.817 3.44e-10 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 13.08 on 33 degrees of freedom
Multiple R-squared:  0.702, Adjusted R-squared:  0.693 
F-statistic: 77.73 on 1 and 33 DF,  p-value: 3.435e-10
# Grafico dei risultati
library(ggplot2)
ggplot(data = test_data, aes(x = speed, y = dist)) +
  geom_point(color = "blue") +
  geom_smooth(method = "lm", se = FALSE, color = "red") +
  ggtitle("Predizione della Distanza di Arresto")

[Torna all’ Indice]

Covarianza e Correlazione Empirica

La covarianza e correlazione empirica sono misure statistiche utilizzate per quantificare la relazione tra due variabili in un insieme di dati osservati. Queste misure sono strettamente legate e sono spesso utilizzate per esaminare la relazione lineare tra due variabili.

Covarianza Empirica:

La covarianza empirica è una misura della tendenza di due variabili a variare insieme. Indica se le due variabili crescono o diminuiscono simultaneamente (covarianza positiva) o se una aumenta mentre l’altra diminuisce (covarianza negativa). La formula per calcolare la covarianza empirica tra due variabili X e Y in un set di dati è data da:

\[ Cov(X,Y) = \frac{1}{n-1} \sum_{i = 1}^n {(X_i - \overline{X})(Y_i - \overline{Y})} \]

Correlazione Empirica:

La correlazione empirica è una versione standardizzata della covarianza empirica e misura la forza e la direzione di una relazione lineare tra due variabili. La correlazione empirica è sempre compresa tra -1 e 1. La formula per calcolare la correlazione empirica tra due variabili X e Y è data da:

\[ Cor(X,Y) = \frac{Cov(X,Y)}{S_X \cdot S_Y} \]

Le misure di covarianza empirica e correlazione empirica sono utilizzate per esaminare la relazione tra variabili in un set di dati e sono particolarmente utili nell’analisi statistica e nell’apprendimento automatico per valutare le associazioni tra le variabili prima di costruire modelli predittivi. La correlazione empirica è più comunemente utilizzata perché fornisce una misura standardizzata della relazione tra variabili ed è meno influenzata dall’unità di misura.

Il coefficiente di Pearson è utile per vedere se due variabili hanno una correlazione lineare o meno. Questo perché non tutte le variabili correlate hanno una relazione lineare.

Esempio:

# Esempio dati casuali
set.seed(123)
x <- rnorm(100)  # Variabile x
y <- 2 * x + rnorm(100)  # Variabile y (correlata a x)

# Calcola la correlazione di Pearson
correlation <- cor(x, y)

# Stampa il valore di correlazione
cat("Correlazione di Pearson tra x e y:", correlation, "\n")
Correlazione di Pearson tra x e y: 0.8786993 

In questo esempio, stiamo generando dati casuali per le variabili x e y. La variabile y è costruita come una trasformazione lineare di x con un termine di errore aggiunto. Poi, utilizziamo la funzione cor() per calcolare la correlazione di Pearson tra x e y.

Un valore vicino a 1 indica una correlazione lineare positiva forte, un valore vicino a -1 indica una correlazione lineare negativa forte, mentre un valore vicino a 0 indica una scarsa correlazione lineare tra le due variabili.

[Torna all’ Indice]

Regressione Lineare Multipla

La “Multiple Linear Regression” (Regressione Lineare Multipla) è una tecnica di modellazione statistica utilizzata per analizzare la relazione tra una variabile dipendente (o target) e due o più variabili indipendenti (o predittive). Questa tecnica estende la semplice regressione lineare, che coinvolge solo una variabile indipendente, a un contesto in cui più variabili indipendenti sono coinvolte nel modello. La regressione lineare multipla è ampiamente utilizzata nell’analisi statistica e nell’apprendimento automatico per fare previsioni o comprendere le relazioni complesse tra variabili.

\[ Y = \beta_0 + \beta_1X_1 + ... + \beta_nX_n + \epsilon \] L’obiettivo principale è stimare i coefficienti β in modo che il modello si adatti meglio ai dati osservati. Questo viene fatto utilizzando metodi di stima, come il metodo dei minimi quadrati, che cerca di minimizzare la somma dei quadrati degli errori residui. Il modello di regressione viene valutato utilizzando metriche di valutazione delle prestazioni come l’errore quadratico medio (RMSE), il coefficiente di determinazione (R-squared) e altri. È importante eseguire test di significatività statistica per i coefficienti delle variabili indipendenti per determinare se esse contribuiscono significativamente al modello.

La regressione lineare multipla è basata su alcune assunzioni, tra cui l’indipendenza degli errori, l’omoschedasticità (varianza costante degli errori), la linearità della relazione e la normalità degli errori.

# Carica il dataset mtcars
data(mtcars)

# Visualizza le prime righe del dataset
head(mtcars)

# Adattamento del modello di regressione lineare multipla
model <- lm(mpg ~ wt + hp + qsec, data = mtcars)

# Visualizza un riepilogo del modello
summary(model)

Call:
lm(formula = mpg ~ wt + hp + qsec, data = mtcars)

Residuals:
    Min      1Q  Median      3Q     Max 
-3.8591 -1.6418 -0.4636  1.1940  5.6092 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) 27.61053    8.41993   3.279  0.00278 ** 
wt          -4.35880    0.75270  -5.791 3.22e-06 ***
hp          -0.01782    0.01498  -1.190  0.24418    
qsec         0.51083    0.43922   1.163  0.25463    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 2.578 on 28 degrees of freedom
Multiple R-squared:  0.8348,    Adjusted R-squared:  0.8171 
F-statistic: 47.15 on 3 and 28 DF,  p-value: 4.506e-11
# Effettua previsioni con il modello
predictions <- predict(model, newdata = mtcars)

# Valuta le prestazioni del modello
SSR <- sum((mtcars$mpg - predictions)^2)  # Somma dei quadrati residui
SST <- sum((mtcars$mpg - mean(mtcars$mpg))^2)  # Somma totale dei quadrati

R_squared <- 1 - (SSR / SST)

cat("R-squared (manual calculation):", R_squared, "\n")
R-squared (manual calculation): 0.8347678 

In sintesi, il modello di regressione lineare multipla suggerisce che il peso del veicolo influenza il consumo di carburante. La potenza del motore e il tempo di accelerazione non sono significative per la spiegazione di questo modello. Nonostante ciò il modello spiega l’83% dei della variazione nei consumi di carburante.

[Torna all’ Indice]

Approcio Matriciale

L’approccio matriciale alla regressione è una forma alternativa di rappresentazione e risoluzione dei modelli di regressione, inclusa la regressione lineare. Questo approccio utilizza notazioni matematiche e matrici per semplificare i calcoli e ottenere soluzioni più efficienti in problemi di regressione lineare.

Ci permette di passare da: \[ Y = \beta_0 + \beta_1X_1 + ... + \beta_nX_n + \epsilon \] a : \[ Y = \beta X + \epsilon \]

La soluzione matriciale per stimare i coefficienti β é: \[ \beta = ((X^T X)^{-1} X^T Y) \]

L’approccio matriciale semplifica la rappresentazione e la risoluzione dei modelli di regressione, specialmente quando si lavora con più variabili indipendenti. Inoltre, è utile per comprendere come eseguire calcoli di regressione in modo più efficiente utilizzando matrici e algebra lineare, specialmente in contesti di apprendimento automatico in cui le dimensioni dei dati possono essere elevate.

# Carica il dataset "swiss" (un dataset di dati demografici svizzeri)
data(swiss)

# Visualizza le prime righe del dataset
head(swiss)

# Crea la matrice delle variabili indipendenti
X <- as.matrix(swiss[, c("Examination", "Education")])

# Aggiungi una colonna di 1 per l'intercetta
X <- cbind(1, X)

# Crea il vettore delle variabili dipendenti
Y <- swiss$Fertility

# Calcola i coefficienti del modello utilizzando l'approccio matriciale
beta <- solve(t(X) %*% X) %*% t(X) %*% Y

# Visualizza i coefficienti del modello
print(beta)
                  [,1]
            85.2532753
Examination -0.5572183
Education   -0.5394570
# Effettua previsioni con il modello matriciale
predictions <- X %*% beta

# Valuta le prestazioni del modello
model <- lm(Y ~ Examination + Education, data = swiss)  # 0 indica di non calcolare l'intercetta
summary(model) 

Call:
lm(formula = Y ~ Examination + Education, data = swiss)

Residuals:
     Min       1Q   Median       3Q      Max 
-15.9935  -6.8894  -0.3621   7.1640  19.2634 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  85.2533     3.0855  27.630   <2e-16 ***
Examination  -0.5572     0.2319  -2.402   0.0206 *  
Education    -0.5395     0.1924  -2.803   0.0075 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 8.982 on 44 degrees of freedom
Multiple R-squared:  0.5055,    Adjusted R-squared:  0.483 
F-statistic: 22.49 on 2 and 44 DF,  p-value: 1.87e-07
  • Esame (Examination): Un aumento nei punteggi di esame è associato a una diminuzione della fertilità nelle regioni svizzere. Questo suggerisce che un migliore stato di salute generale, misurato tramite l’esame, è correlato a una fertilità più bassa.
  • Educazione (Education): Un aumento nel livello di educazione è correlato a una riduzione della fertilità. Le regioni con un livello di istruzione più elevato tendono ad avere una fertilità più bassa.

[Torna all’ Indice]

Interpretazione Geometrica

L’interpretazione geometrica della regressione lineare è un approccio concettuale che utilizza uno spazio tridimensionale (o superiore) per rappresentare visivamente il modello di regressione. In questo spazio, ogni punto rappresenta un’osservazione nel dataset, e un piano (o iperpiano) rappresenta il modello di regressione. L’obiettivo è trovare il piano (o iperpiano) che minimizza la somma dei quadrati delle distanze verticali tra i punti dati e il piano (o iperpiano). Questo fornisce una visualizzazione intuitiva di come i coefficienti del modello vengono stimati per ottenere la migliore “ajustement” ai dati, minimizzando gli errori residui. L’interpretazione geometrica aiuta a comprendere i principi fondamentali della regressione lineare e può essere applicata a problemi più complessi con più variabili indipendenti.

library(knitr)
library(plotly)
Loading required package: ggplot2
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio

Attaching package: ‘plotly’

The following object is masked from ‘package:ggplot2’:

    last_plot

The following object is masked from ‘package:stats’:

    filter

The following object is masked from ‘package:graphics’:

    layout
# Genera dati casuali
set.seed(123)
n <- 50
X1 <- rnorm(n)
X2 <- rnorm(n)
Y <- 2 * X1 + 3 * X2 + rnorm(n)

# Crea un dataframe con le variabili
data <- data.frame(X1, X2, Y)

# Adatta il modello di regressione lineare
model <- lm(Y ~ X1 + X2, data = data)
summary(model)

Call:
lm(formula = Y ~ X1 + X2, data = data)

Residuals:
     Min       1Q   Median       3Q      Max 
-1.88137 -0.74056 -0.06374  0.52516  2.27045 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  -0.2299     0.1431  -1.607    0.115    
X1            2.0252     0.1540  13.150   <2e-16 ***
X2            2.8304     0.1575  17.973   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.9975 on 47 degrees of freedom
Multiple R-squared:  0.9107,    Adjusted R-squared:  0.9069 
F-statistic: 239.8 on 2 and 47 DF,  p-value: < 2.2e-16
# Creazione di una griglia di punti
x1_range <- seq(min(X1), max(X1), length = 20)
x2_range <- seq(min(X2), max(X2), length = 20)
grid <- expand.grid(X1 = x1_range, X2 = x2_range)

# Calcolo delle previsioni del modello sulla griglia
grid$Y_pred <- predict(model, newdata = grid)

# Creazione del plot 3D con plotly
 plot_ly(data, x = ~X1, y = ~X2, z = ~Y, type = "scatter3d", mode = "markers", marker = list(size = 5, color = "blue")) %>%
   add_surface(
     x = x1_range,
     y = x2_range,
     z = matrix(grid$Y_pred, nrow = length(x1_range), ncol = length(x2_range), byrow = TRUE),
     colors = "red",
     opacity = 0.7
   ) %>%
   layout(scene = list(xaxis = list(title = "X1"), yaxis = list(title = "X2"), zaxis = list(title = "Y")))
NA

L’interpretazione geometrica ci consente di vedere come il piano di regressione si adatta ai dati nello spazio tridimensionale e come i coefficienti stimati influenzano la posizione e l’inclinazione del piano rispetto ai dati osservati. Questo fornisce una visualizzazione intuitiva della relazione tra le variabili indipendenti e dipendenti nel contesto della regressione lineare.

[Torna all’ Indice]

Distribuzione F & Anova Table

L’ANOVA valuta globalmente se almeno una delle variabili indipendenti ha un effetto significativo sulla variabile dipendente, fornisce una statistica F e il relativo p-value. Un p-value basso suggerisce che almeno una delle variabili indipendenti è significativa nel modello. L’ANOVA fornisce quindi una visione complessiva della significatività del modello nel suo complesso.

L’analisi della varianza (ANOVA) e i “signif. codes” nel summary del modello forniscono informazioni simili, ma si concentrano su aspetti diversi dell’analisi.

I “signif. codes” nel summary del modello forniscono una valutazione variabile per variabile, indicando la significatività statistica di ciascun coefficiente. Utilizza asterischi (*) o altri simboli per indicare il livello di significatività, ad esempio, “***” potrebbe indicare un livello di significatività molto elevato (p-value molto basso), mentre ” ” (spazio) potrebbe indicare non significativo. Questa parte del summary fornisce una visione più dettagliata sulla significatività di ciascuna variabile indipendente separatamente.

L’ANOVA valuta la significatività del modello nel suo insieme, mentre i “signif. codes” nel summary forniscono una visione dettagliata della significatività di ciascuna variabile indipendente.

Esempio 1:

# Creiamo un dataset fittizio
set.seed(123)
data <- data.frame(
  Gruppo = rep(c("A", "B", "C"), each = 20),
  Punteggio = rnorm(60, mean = c(70, 75, 80), sd = 5)
)

# Eseguiamo l'ANOVA
anova_result <- aov(Punteggio ~ Gruppo, data = data)

# Visualizziamo la tabella ANOVA
summary(anova_result)
            Df Sum Sq Mean Sq F value Pr(>F)
Gruppo       2   11.3    5.65   0.143  0.867
Residuals   57 2255.9   39.58               

In questo esempio, eseguiamo un’ANOVA a un fattore per valutare le differenze nei punteggi tra i gruppi A, B e C. Il rapporto F e il valore p ci permettono di determinare se le differenze tra i gruppi sono statisticamente significative.

I risultati suggeriscono che non ci sono differenze statisticamente significative tra i gruppi, ossia il variare del gruppo non influenza significativamente la variabile dipendente. La varianza tra i gruppi è molto piccola rispetto alla varianza all’interno dei gruppi, e il test F non è significativo. Questo può indicare che i gruppi sono simili tra loro per quanto riguarda la variabile in studio.

Esempio 2:

# Creiamo un dataset fittizio
set.seed(123)
data <- data.frame(
  Genere = rep(c("Maschio", "Femmina"), each = 50),
  Trattamento = rep(c("A", "B"), times = 50),
  Punteggio = rnorm(100, mean = c(75, 80), sd = 5)
)

# Eseguiamo l'ANOVA a due fattori
anova_result <- aov(Punteggio ~ Genere * Trattamento, data = data)

# Visualizziamo la tabella ANOVA
summary(anova_result)
                   Df Sum Sq Mean Sq F value   Pr(>F)    
Genere              1    7.8     7.8   0.367    0.546    
Trattamento         1  575.8   575.8  26.953 1.16e-06 ***
Genere:Trattamento  1    2.6     2.6   0.121    0.729    
Residuals          96 2050.8    21.4                     
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

In questo esempio, eseguiamo un’ANOVA a due fattori per esaminare le differenze nei punteggi in base al genere e al trattamento.

Dalla tabella dell’ANOVA fornita, possiamo trarre le seguenti conclusioni:

  • Il fattore “Trattamento” ha un forte effetto sulla variabile dipendente, con un valore di F elevato e un p-value molto basso, indicando che le differenze tra i trattamenti sono statisticamente significative (***).
  • Il fattore “Genere” non ha un effetto significativo sulla variabile dipendente, con un valore di F basso e un p-value elevato.
  • L’interazione tra “Genere” e “Trattamento” non ha un effetto significativo sulla variabile dipendente, con un valore di F e un p-value non significativi.

I risultati dell’ANOVA suggeriscono che il “Trattamento” è il principale driver delle differenze osservate nella variabile dipendente, mentre il “Genere” e l’interazione tra “Genere” e “Trattamento” non sembrano avere un effetto significativo.

  • Un valore F maggiore di 1 suggerisce che i parametri o i fattori sono significativi, poiché la varianza spiegata è maggiore della varianza non spiegata.
  • Un valore F vicino a 1 indica che il modello non spiega in modo significativo la variabilità nei dati.
  • Il valore p associato all’F-value fornisce la probabilità che i risultati osservati siano dovuti al caso. Un valore p basso (di solito inferiore a 0.05) indica una significatività elevata, mentre un valore p alto suggerisce una mancanza di significatività.

Sistema di ipotesi:

Nell’analisi statistica in cui si calcola un valore F, ci sono due ipotesi principali: l’ipotesi nulla (H0) e l’ipotesi alternativa (H1).

Ipotesi Nulla (H0): L’ipotesi nulla afferma che non ci sono differenze significative tra i gruppi o i fattori considerati. In altre parole, l’ipotesi nulla sostiene che i parametri del modello o i fattori non hanno un effetto significativo sul risultato o che le differenze osservate sono casuali.

Ipotesi Alternativa (H1 o HA): L’ipotesi alternativa è il contrario dell’ipotesi nulla. Sostiene che ci sono differenze significative tra i gruppi o i fattori considerati, e che le differenze osservate non sono casuali, ma sono dovute a un effetto significativo dei parametri del modello o dei fattori.

Continuiamo l’esempio di prima:

model <- lm(Punteggio ~ Genere * Trattamento, data = data)
summary(model)

Call:
lm(formula = Punteggio ~ Genere * Trattamento, data = data)

Residuals:
     Min       1Q   Median       3Q      Max 
-12.3383  -3.1482  -0.1363   3.1717  10.9341 

Coefficients:
                           Estimate Std. Error t value Pr(>|t|)    
(Intercept)                 75.6716     0.9244  81.861  < 2e-16 ***
GenereMaschio               -0.2383     1.3073  -0.182 0.855741    
TrattamentoB                 5.1208     1.3073   3.917 0.000168 ***
GenereMaschio:TrattamentoB  -0.6434     1.8488  -0.348 0.728578    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 4.622 on 96 degrees of freedom
Multiple R-squared:  0.2223,    Adjusted R-squared:  0.198 
F-statistic: 9.147 on 3 and 96 DF,  p-value: 2.206e-05
# Estraiamo il valore p
p_value <- anova_summary[[1]][["Pr(>F)"]][3]  # Usiamo [3] per estrarre il valore relativo all'interazione


# Scegliamo un livello di significatività (alpha)
alpha <- 0.05

# Valutiamo se rifiutare l'ipotesi nulla
if (p_value < alpha) {
  cat("Rifiutiamo l'ipotesi nulla. Ci sono differenze significative tra i gruppi.\n")
} else {
  cat("Non rifiutiamo l'ipotesi nulla. Non ci sono differenze significative tra i gruppi.\n")
}
Non rifiutiamo l'ipotesi nulla. Non ci sono differenze significative tra i gruppi.

La F-statistic nel summary di un modello lineare (lm) rappresenta la statistica del test F per l’intero modello. Questo test verifica se c’è almeno una variabile indipendente nel modello che è significativamente associata alla variabile dipendente. In altre parole, valuta l’ipotesi nulla che tutti i coefficienti delle variabili indipendenti nel modello siano uguali a zero (cioè che non ci siano effetti).

In breve la F-statistic suggerisce che almeno una delle interazioni tra “Genere” e “Trattamento” o almeno una delle principali effetti è significativa nel modello.

[Torna all’ Indice]

Modelli Nidificati

Nei modelli statistici, un “nested model” si verifica quando un modello più complesso o generale può essere suddiviso o semplificato in un modello più semplice o specifico. Il modello più semplice è considerato “nidificato” all’interno del modello più complesso, poiché contiene un sottoinsieme di parametri o vincoli del modello più generale.

Nel contesto della regressione, i modelli nidificati sono spesso utilizzati per testare l’aggiunta di variabili indipendenti al modello al fine di valutare se le variabili aggiuntive migliorano significativamente la capacità di previsione o spiegazione del modello. I modelli nidificati sono anche utilizzati in contesti come l’analisi della varianza (ANOVA), l’analisi della devianza nei modelli lineari generalizzati (che vedremo più avanti) e altre procedure statistiche.

Esempio di Modelli di Regressione Nidificati:

Supponiamo di voler creare un modello di regressione per prevedere il reddito di una persona basandoci su quattro variabili indipendenti: età, istruzione, esperienza lavorativa e genere. Il modello completo potrebbe essere:

Modello Completo

\[ Reddito = \beta_0 + \beta_1 \cdot Età + \beta_2 \cdot Istruzione + \beta_3 \cdot Esperienza + \beta_4 \cdot Genere \] Tuttavia, potremmo essere interessati a valutare se l’aggiunta della variabile “genere” migliora significativamente la capacità predittiva del modello. In tal caso, il modello senza “genere” è nidificato all’interno del modello completo:

Modello Nidificato

\[ Reddito' = \beta_0 + \beta_1 \cdot Età + \beta_2 \cdot Istruzione + \beta_3 \cdot Esperienza \]

In questo esempio, il Modello 1 è il modello completo e il Modello 2 è il modello nidificato senza il parametro per “genere”. Valutiamo tramite un ANOVA quale dei due modelli sia considerato più significativo.

# Creiamo dati fittizi
set.seed(123)
n <- 100
eta <- rnorm(n, mean = 35, sd = 5)
istruzione <- rnorm(n, mean = 12, sd = 2)
esperienza <- rnorm(n, mean = 10, sd = 3)
genere <- sample(c("Maschio", "Femmina"), n, replace = TRUE)
reddito <- 20 + 2 * eta + 3 * istruzione + 5 * esperienza + ifelse(genere == "Maschio", 4, 0) + rnorm(n, mean = 0, sd = 5)

# Creiamo un dataframe con i dati
data <- data.frame(eta, istruzione, esperienza, genere, reddito)

# Modello completo
modello_completo <- lm(reddito ~ eta + istruzione + esperienza + genere, data = data)

# Modello nidificato senza "genere"
modello_nidificato <- lm(reddito ~ eta + istruzione + esperienza, data = data)

# Test F per confrontare i modelli
anova_result <- anova(modello_nidificato, modello_completo)

# Visualizziamo la tabella ANOVA
print(anova_result)
Analysis of Variance Table

Model 1: reddito ~ eta + istruzione + esperienza
Model 2: reddito ~ eta + istruzione + esperienza + genere
  Res.Df    RSS Df Sum of Sq      F    Pr(>F)    
1     96 3137.3                                  
2     95 2606.6  1    530.69 19.342 2.852e-05 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
# Scegliamo un livello di significatività (alpha)
alpha <- 0.05

# Valutiamo se rifiutare l'ipotesi nulla
if (anova_result[2, "Pr(>F)"] < alpha) {
  cat("La rimozione di 'genere' non migliora significativamente il modello.\n")
} else {
  cat("La rimozione di 'genere' migliora significativamente il modello.\n")
}
La rimozione di 'genere' non migliora significativamente il modello.
# R Squared dei due modelli
print("Modello completo ") 
[1] "Modello completo "
summary(modello_completo)$r.squared
[1] 0.9155659
print("Modello annidato ")
[1] "Modello annidato "
summary(modello_nidificato)$r.squared
[1] 0.8983755

[Torna all’ Indice]

Selezione delle variabili

La “variable selection” è un processo attraverso il quale si scelgono le variabili più rilevanti da includere in un modello statistico. Questo processo è utile per semplificare i modelli, migliorare la capacità predittiva e la comprensione dei dati, ridurre l’overfitting e aumentare l’efficienza computazionale.

Un metodo comune per la selezione delle variabili in R coinvolge l’utilizzo dell’Information Criterion (Criterio d’Informazione) di Akaike (AIC) insieme alla funzione step().

AIC (Akaike’s Information Criterion):

Il Criterio d’Informazione di Akaike (AIC) è una metrica che misura la qualità di un modello statistico. L’obiettivo dell’AIC è trovare il miglior compromesso tra la bontà di adattamento del modello ai dati e la sua complessità. L’AIC tiene conto della funzione di verosimiglianza del modello e penalizza i modelli con un numero maggiore di parametri. L’AIC è definito come:

\[ AIC = -2logLikelihood + 2k \]

Dove:

  • “log-likelihood” è il logaritmo della funzione di verosimiglianza del modello.
  • “k” è il numero di parametri stimati nel modello. Un valore AIC più basso indica un modello migliore, in quanto indica un migliore adattamento ai dati con meno complessità.

Funzione step():

La funzione step() in R è utilizzata per effettuare la selezione delle variabili basata su criteri come l’AIC. Consente di confrontare e selezionare i modelli in modo automatico aggiungendo o rimuovendo variabili dal modello, fino a trovare il modello con l’AIC più basso. La sintassi di base della funzione step() è la seguente:

#step(modello_iniziale, direction = "both", scope = list(lower = modello_minimo, upper = modello_massimo))
  • modello_iniziale è il modello di partenza che desideri semplificare o migliorare.
  • direction può essere “forward”, “backward”, o “both” e specifica se aggiungere, rimuovere o entrambi i tipi di variabili durante la selezione.
  • scope specifica l’intervallo dei modelli da considerare durante la selezione. Il - “modello_minimo” rappresenta il modello più semplice possibile (ad esempio, un modello con solo l’intercetta), mentre il “modello_massimo” rappresenta il modello più complesso (il modello completo con tutte le variabili).
# Carica il dataset di esempio
data(mtcars)

# Crea un modello lineare iniziale
all <- lm(mpg ~ ., data = mtcars)

# Esegui la selezione delle variabili basata su AIC
best <- step(all, direction = "backward")
Start:  AIC=70.9
mpg ~ cyl + disp + hp + drat + wt + qsec + vs + am + gear + carb

       Df Sum of Sq    RSS    AIC
- cyl   1    0.0799 147.57 68.915
- vs    1    0.1601 147.66 68.932
- carb  1    0.4067 147.90 68.986
- gear  1    1.3531 148.85 69.190
- drat  1    1.6270 149.12 69.249
- disp  1    3.9167 151.41 69.736
- hp    1    6.8399 154.33 70.348
- qsec  1    8.8641 156.36 70.765
<none>              147.49 70.898
- am    1   10.5467 158.04 71.108
- wt    1   27.0144 174.51 74.280

Step:  AIC=68.92
mpg ~ disp + hp + drat + wt + qsec + vs + am + gear + carb

       Df Sum of Sq    RSS    AIC
- vs    1    0.2685 147.84 66.973
- carb  1    0.5201 148.09 67.028
- gear  1    1.8211 149.40 67.308
- drat  1    1.9826 149.56 67.342
- disp  1    3.9009 151.47 67.750
- hp    1    7.3632 154.94 68.473
<none>              147.57 68.915
- qsec  1   10.0933 157.67 69.032
- am    1   11.8359 159.41 69.384
- wt    1   27.0280 174.60 72.297

Step:  AIC=66.97
mpg ~ disp + hp + drat + wt + qsec + am + gear + carb

       Df Sum of Sq    RSS    AIC
- carb  1    0.6855 148.53 65.121
- gear  1    2.1437 149.99 65.434
- drat  1    2.2139 150.06 65.449
- disp  1    3.6467 151.49 65.753
- hp    1    7.1060 154.95 66.475
<none>              147.84 66.973
- am    1   11.5694 159.41 67.384
- qsec  1   15.6830 163.53 68.200
- wt    1   27.3799 175.22 70.410

Step:  AIC=65.12
mpg ~ disp + hp + drat + wt + qsec + am + gear

       Df Sum of Sq    RSS    AIC
- gear  1     1.565 150.09 63.457
- drat  1     1.932 150.46 63.535
<none>              148.53 65.121
- disp  1    10.110 158.64 65.229
- am    1    12.323 160.85 65.672
- hp    1    14.826 163.35 66.166
- qsec  1    26.408 174.94 68.358
- wt    1    69.127 217.66 75.350

Step:  AIC=63.46
mpg ~ disp + hp + drat + wt + qsec + am

       Df Sum of Sq    RSS    AIC
- drat  1     3.345 153.44 62.162
- disp  1     8.545 158.64 63.229
<none>              150.09 63.457
- hp    1    13.285 163.38 64.171
- am    1    20.036 170.13 65.466
- qsec  1    25.574 175.67 66.491
- wt    1    67.572 217.66 73.351

Step:  AIC=62.16
mpg ~ disp + hp + wt + qsec + am

       Df Sum of Sq    RSS    AIC
- disp  1     6.629 160.07 61.515
<none>              153.44 62.162
- hp    1    12.572 166.01 62.682
- qsec  1    26.470 179.91 65.255
- am    1    32.198 185.63 66.258
- wt    1    69.043 222.48 72.051

Step:  AIC=61.52
mpg ~ hp + wt + qsec + am

       Df Sum of Sq    RSS    AIC
- hp    1     9.219 169.29 61.307
<none>              160.07 61.515
- qsec  1    20.225 180.29 63.323
- am    1    25.993 186.06 64.331
- wt    1    78.494 238.56 72.284

Step:  AIC=61.31
mpg ~ wt + qsec + am

       Df Sum of Sq    RSS    AIC
<none>              169.29 61.307
- am    1    26.178 195.46 63.908
- qsec  1   109.034 278.32 75.217
- wt    1   183.347 352.63 82.790

In questo esempio, partiamo da un modello lineare completo che utilizza tutte le variabili di mtcars, e poi utilizziamo step() per eseguire la selezione delle variabili basata su AIC. Alla fine, otteniamo il modello con l’AIC più basso, che dovrebbe essere una versione semplificata del modello iniziale con solo le variabili più rilevanti.

La “variable selection” utilizzando AIC e step() è un potente strumento per migliorare la qualità e l’interpretabilità dei modelli statistici, in particolare quando si hanno molti potenziali predittori.

[Torna all’ Indice]

Predizioni Categoriche

Nell’analisi statistica, i “categorical predictors” sono variabili che rappresentano categorie o gruppi distinti anziché valori numerici. Queste variabili sono anche conosciute come variabili qualitative o fattori. Ad esempio, il genere (maschio/femmina), il livello di istruzione (scuola elementare, scuola media, laurea), o il tipo di prodotto (A, B, C) sono esempi di predittori categorici. Quando si utilizzano predittori categorici in un modello statistico, è importante considerare come gestire e interpretare questi dati.

Una considerazione fondamentale è come rappresentare le variabili categoriche nel modello. Solitamente, vengono utilizzate delle variabili dummy (variabili indicatrici) per rappresentare le categorie. Ad esempio, nel caso del genere (maschio/femmina), potrebbero essere create due variabili dummy, una per il maschio e una per la femmina. Queste variabili dummy prendono il valore 1 o 0 a seconda dell’appartenenza alla categoria. Questo approccio consente al modello di catturare l’effetto della categoria sulla variabile dipendente.

Oltre alla rappresentazione delle variabili categoriche, è importante considerare le interazioni tra i predittori. Le interazioni si verificano quando l’effetto di una variabile categorica sul risultato dipende da un’altra variabile. Ad esempio, l’effetto del livello di istruzione sul reddito potrebbe variare in base al genere. In questo caso, c’è un’interazione tra il livello di istruzione e il genere.

Per esaminare le interazioni tra predittori categorici, è possibile utilizzare l’analisi della varianza (ANOVA) o i modelli lineari generalizzati (che vedremo più avanti). Le interazioni possono fornire informazioni preziose sull’influenza combinata delle variabili categoriche sul risultato.

# Creiamo dati fittizi
set.seed(123)
n <- 100
genere <- sample(c("Maschio", "Femmina"), n, replace = TRUE)
istruzione <- rep(c("Elementare", "Media", "Laurea"), length.out = n )
reddito <- 30 + ifelse(genere == "Maschio", 5, 0) + ifelse(istruzione == "Laurea", 10, 0) + rnorm(n, mean = 0, sd = 5)

# Creiamo un dataframe con i dati
data <- data.frame(genere, istruzione, reddito)

# Modello con interazione tra genere e istruzione
modello <- lm(reddito ~ genere * istruzione, data = data)

# Visualizziamo i risultati
summary(modello)

Call:
lm(formula = reddito ~ genere * istruzione, data = data)

Residuals:
    Min      1Q  Median      3Q     Max 
-9.3888 -3.0121 -0.6269  2.6272 11.0710 

Coefficients:
                               Estimate Std. Error t value Pr(>|t|)    
(Intercept)                     27.8429     1.2794  21.763  < 2e-16 ***
genereMaschio                    5.8726     1.6681   3.521 0.000666 ***
istruzioneLaurea                12.0839     1.8438   6.554 2.98e-09 ***
istruzioneMedia                  3.3778     1.7519   1.928 0.056860 .  
genereMaschio:istruzioneLaurea  -1.3699     2.3856  -0.574 0.567186    
genereMaschio:istruzioneMedia   -0.8084     2.3586  -0.343 0.732535    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 4.787 on 94 degrees of freedom
Multiple R-squared:  0.5839,    Adjusted R-squared:  0.5618 
F-statistic: 26.38 on 5 and 94 DF,  p-value: < 2.2e-16
anova(modello, test = "chi")
Analysis of Variance Table

Response: reddito
                  Df  Sum Sq Mean Sq F value    Pr(>F)    
genere             1  738.22  738.22 32.2149 1.525e-07 ***
istruzione         2 2277.06 1138.53 49.6837 1.892e-15 ***
genere:istruzione  2    7.66    3.83  0.1672    0.8463    
Residuals         94 2154.06   22.92                      
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
# Grafico reddito per soli maschi e sole femmine
ggplot(data = data, aes(x = istruzione, y = reddito, fill = genere)) +
  geom_boxplot() +
  labs(x = "Istruzione", y = "Reddito")

In questo esempio, stiamo creando dati fittizi con due predittori categorici: “genere” e “istruzione”. Il modello lineare include un’interazione tra questi due predittori. La tabella dei risultati summary(modello) mostra come i predittori categorici e l’interazione influenzano il reddito.

Possiamo concludere che il genere e il livello di istruzione hanno un effetto significativo sul reddito, mentre le interazioni tra genere e istruzione non sono significative in questo modello. Il modello nel suo complesso è significativo e in grado di spiegare una parte della variazione nel reddito.

Fattori con più di due categorie:

Quando si affrontano fattori con più di due livelli (categorie), è necessario considerare come gestire queste variabili nel modello. In generale, un fattore con k livelli richiede la creazione di k-1 variabili dummy per evitare la “dummy variable trap”. Questo si verifica quando le variabili dummy sono linearmente dipendenti e possono portare a problemi di multicollinearità.

Ad esempio, se abbiamo una variabile “colore” con tre livelli (rosso, verde, blu), dovremmo creare due variabili dummy per rappresentarla. Una rappresenterà il rosso e l’altra il verde. Se entrambe le variabili dummy sono uguali a 0, ciò significa che il colore è blu. Questo evita la trap della variabile dummy.

# Creiamo dati fittizi
set.seed(123)
n <- 100
colore <- rep(c("Rosso", "Verde", "Blu"), length.out = n )
voto <- rnorm(n, mean = 50, sd = 10)

# Creiamo un dataframe con i dati
data <- data.frame(colore, voto)

# Modello con un fattore con più di due livelli
modello <- lm(voto ~ colore, data = data)

# Visualizziamo i risultati
summary(modello)

Call:
lm(formula = voto ~ colore, data = data)

Residuals:
     Min       1Q   Median       3Q      Max 
-23.6349  -6.1247  -0.4198   5.7870  21.9547 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  50.5432     1.5932  31.725   <2e-16 ***
coloreRosso   1.8459     2.2364   0.825    0.411    
coloreVerde  -0.8084     2.2531  -0.359    0.721    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 9.152 on 97 degrees of freedom
Multiple R-squared:  0.01508,   Adjusted R-squared:  -0.005228 
F-statistic: 0.7426 on 2 and 97 DF,  p-value: 0.4786

I risultati indicano che il colore del prodotto (rosso o verde) non ha un impatto significativo sul voto. L’intercetta, che rappresenta il colore “Blu,” è significativa, ma il modello nel suo insieme non è molto efficace nel spiegare la variazione nei voti.

[Torna all’ Indice]

Controllo del Modello

Il Model Checking è una fase cruciale nell’analisi statistica, specialmente quando si adotta un modello di regressione. Durante questa fase, si valuta se il modello soddisfa le principali assunzioni dei modelli lineari. Le quattro assunzioni principali da verificare sono:

  • Linearity (Linearità): Questa assunzione afferma che la risposta (variabile dipendente) può essere scritta come una combinazione lineare delle variabili predittive (variabili indipendenti). In altre parole, il modello dovrebbe essere in grado di catturare il rapporto tra le variabili in modo lineare, con un certo grado di rumore residuo. La linearità può essere verificata attraverso grafici di dispersione o grafici residui.
  • Independence (Indipendenza): Questa assunzione richiede che gli errori (residui) del modello siano indipendenti l’uno dall’altro. Ciò significa che il valore di errore per un’osservazione non è influenzato dal valore di errore per un’altra osservazione. L’indipendenza può essere verificata osservando i grafici dei residui in sequenza temporale o spaziale, a seconda del contesto.
  • Normality (Normalità): L’assunzione di normalità richiede che i residui del modello seguano una distribuzione normale. Questo è importante perché molte procedure statistiche si basano sull’ipotesi di normalità dei residui. La normalità può essere verificata tramite grafici quantile-quantile (QQ plot) o istogrammi dei residui.
  • Equal Variance (Varianza Uniforme): Questa assunzione, chiamata anche omoschedasticità, richiede che la varianza dei residui sia costante in tutti i livelli delle variabili predittive. In altre parole, non dovrebbe esserci alcun modello discernibile nella varianza dei residui. La varianza uniforme può essere verificata osservando i grafici dei residui rispetto ai valori predetti.

Per verificare queste assunzioni, i Residuals-based displays (grafici basati sui residui) sono spesso utilizzati. Questi includono:

  • Scatterplot dei residui: Un grafico dei residui contro i valori previsti o le variabili predittive. Questo può rivelare se c’è una struttura non lineare nei residui.
  • Grafico di sequenza temporale dei residui: Utilizzato quando i dati sono raccolti nel tempo, questo grafico può rivelare dipendenze temporali nei residui.
  • QQ-plot (Quantile-Quantile plot): Questo grafico confronta i quantili dei residui con quelli di una distribuzione normale. Se i punti del grafico seguono una linea retta, i residui sono approssimativamente normali.
  • Istogramma dei residui: Un istogramma dei residui può dare un’idea della loro distribuzione e normalità.

Rispettare queste assunzioni è importante per garantire che le stime del modello siano affidabili e che le conclusioni siano valide. Se una o più di queste assunzioni non sono soddisfatte, potrebbero essere necessarie correzioni al modello o ai dati stessi.

[Torna all’ Indice]

Transformazioni

Le trasformazioni sono una tecnica utilizzata nella modellazione statistica per modificare le relazioni tra variabili al fine di soddisfare meglio le assunzioni del modello. Le trasformazioni possono essere utili quando le relazioni tra le variabili non sono lineari o quando le assunzioni di omoschedasticità o normalità dei residui non sono soddisfatte. Di seguito, affrontiamo i seguenti argomenti relativi alle trasformazioni:

  • Variance Stabilizing Transformations (Trasformazioni per Stabilizzare la Varianza): In alcuni casi, la varianza dei dati può variare in modo non costante con il cambiare del valore medio. Questo fenomeno è noto come eteroschedasticità. Le trasformazioni possono essere utilizzate per stabilizzare la varianza, rendendo la relazione tra il valore medio e la varianza più costante. Un esempio comune è la trasformazione di Box-Cox.

  • Box-Cox Transform: La trasformazione di Box-Cox è una tecnica utilizzata per stabilizzare la varianza e rendere i dati approssimativamente normali. È definita come:

\[ y(\lambda) = \begin{cases} \frac{(y^\lambda - 1)}{\lambda} & \text{se } \lambda \neq 0 \\ \log(y) & \text{se } \lambda = 0 \end{cases} \]

Dove y sono i dati originali e λ è il parametro di trasformazione. È possibile calcolare il valore ottimale di λ che massimizza la normalità dei dati.

library(ggplot2)
library(MASS)
library(gridExtra)

# Genera dati casuali
set.seed(123)
data <- data.frame(y = rgamma(100, shape = 2, scale = 1))

# Applica la trasformazione di Box-Cox
result <- boxcox(y ~ 1, data = data)

lambda <- result$x[which.max(result$y)]
transformed_data <- if (lambda == 0) log(data$y) else ((data$y^lambda - 1) / lambda)

# Visualizza il valore ottimale di lambda
cat("Valore ottimale di lambda: ", lambda, "\n")
Valore ottimale di lambda:  0.3838384 
# Crea un dataframe con i dati originali e trasformati
plot_data <- data.frame(Original = data$y, Transformed = transformed_data)

# Plotta i dati originali
plot_original <- ggplot(plot_data, aes(x = Original)) +
  geom_histogram(binwidth = 0.5, fill = "blue", alpha = 0.7) +
  labs(title = "Distribuzione dei dati originali")

# Plotta i dati trasformati
plot_transformed <- ggplot(plot_data, aes(x = Transformed)) +
  geom_histogram(binwidth = 0.1, fill = "green", alpha = 0.7) +
  labs(title = "Distribuzione dei dati trasformati")

# Mostra i grafici sulla stessa riga
grid.arrange(plot_original, plot_transformed, ncol = 2)

  • Polynomials (Polinomi): Le trasformazioni polinomiali consentono di modellare relazioni non lineari tra variabili. È possibile aggiungere termini polinomiali al modello di regressione per catturare curve o relazioni più complesse. Ad esempio, si possono utilizzare polinomi di secondo grado per modellare una relazione quadratica tra una variabile indipendente e la variabile dipendente. L’aggiunta di termini polinomiali può migliorare l’adattamento del modello ai dati, ma è importante evitare di aggiungere troppi termini polinomiali per evitare l’overfitting.
# Modello lineare con un termine polinomiale di secondo grado
model <- lm(y ~ x + I(x^2), data = data)
  • Transformations of Predictor Variables (Trasformazioni delle Variabili Predittive): Le trasformazioni delle variabili predittive sono utilizzate per adattare i dati in modo che soddisfino meglio le assunzioni del modello. Queste trasformazioni coinvolgono la modifica delle variabili indipendenti piuttosto che della variabile dipendente. Possono essere utilizzate per rendere le relazioni tra le variabili più lineari o per stabilizzare la varianza. Ad esempio, è possibile applicare una trasformazione logaritmica o una radice quadrata a una variabile predittiva per renderla più lineare nei confronti della variabile dipendente.
# Creiamo dati fittizi
set.seed(123)
X <- rnorm(100, mean = 10, sd = 2)
Y <- 2 * X + rnorm(100, mean = 0, sd = 1)

# Creiamo un dataframe con i dati
data <- data.frame(X, Y)

# Modello lineare senza trasformazione
model_no_transform <- lm(Y ~ X, data = data)

# Visualizziamo il summary del modello senza trasformazione
summary(model_no_transform)

Call:
lm(formula = Y ~ X, data = data)

Residuals:
    Min      1Q  Median      3Q     Max 
-1.9073 -0.6835 -0.0875  0.5806  3.2904 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  0.15956    0.55265   0.289    0.773    
X            1.97376    0.05344  36.935   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.9707 on 98 degrees of freedom
Multiple R-squared:  0.933, Adjusted R-squared:  0.9323 
F-statistic:  1364 on 1 and 98 DF,  p-value: < 2.2e-16
# Trasformiamo la variabile X applicando il logaritmo
data$X_transformed <- log(data$X)

# Modello lineare con la variabile X trasformata
model_with_transform <- lm(Y ~ X_transformed, data = data)

# Visualizziamo il summary del modello con la variabile X trasformata
summary(model_with_transform)

Call:
lm(formula = Y ~ X_transformed, data = data)

Residuals:
    Min      1Q  Median      3Q     Max 
-1.9290 -0.7441 -0.1202  0.5388  3.3305 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept)   -24.1696     1.2961  -18.65   <2e-16 ***
X_transformed  19.2819     0.5608   34.38   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.037 on 98 degrees of freedom
Multiple R-squared:  0.9235,    Adjusted R-squared:  0.9227 
F-statistic:  1182 on 1 and 98 DF,  p-value: < 2.2e-16

Le trasformazioni sono strumenti potenti per adattare i modelli ai dati in modo più accurato quando le relazioni tra variabili non sono lineari o quando le assunzioni del modello non sono soddisfatte. Tuttavia, è importante scegliere con attenzione le trasformazioni per evitare il sovradattamento e garantire che i risultati siano interpretabili.

[Torna all’ Indice]

Multicollinearità

La multicollinearità si verifica quando due o più variabili indipendenti in un modello di regressione sono fortemente correlate tra loro. Questa correlazione tra le variabili indipendenti può rendere difficile l’interpretazione del modello e portare a stime poco affidabili dei coefficienti di regressione. La presenza di multicollinearità può causare un aumento del Variance Inflation Factor (VIF), una misura comune utilizzata per valutare la multicollinearità tra le variabili indipendenti in un modello di regressione. Un alto VIF per una variabile indica che quella variabile è fortemente correlata con le altre variabili indipendenti nel modello.

Variance Inflation Factor:

Il VIF di ciascuna variabile indipendente è calcolato come il rapporto della varianza dell’errore standard del coefficiente di regressione stimato per quella variabile rispetto alla varianza dell’errore standard se la variabile fosse stata completamente non correlata alle altre variabili indipendenti. In generale, un VIF superiore a 5 o 10 è spesso considerato un segno di multicollinearità significativa.

\[ VIF_i = (X^TX)_{i+1,i+1}^{-1}*ns^2_{X_i} \ \ oppure \ \ VIF_i = \frac{1}{1-R^2_i} \]

# Load the necessary library
library(car)

# Create a sample dataset with multiple predictor variables
set.seed(123)
data <- data.frame(
  X1 = rnorm(100),
  X2 = rnorm(100),
  X3 = rnorm(100),
  X4 = rnorm(100)
)

# Add a dependent variable (response)
data$Y <- 2 * data$X1 + 3 * data$X2 + 1.5 * data$X3 + rnorm(100)

# Fit a linear regression model
model <- lm(Y ~ X1 + X2 + X3 + X4, data = data)

# Calculate VIF
vif_values <- vif(model)

# Print the VIF values
vif_values
      X1       X2       X3       X4 
1.021515 1.004920 1.020348 1.006429 

Tutti i valori VIF sono vicini a 1, il che suggerisce che non c’è una forte multicollinearità tra le variabili predittive X1, X2, X3 e X4. Questo è un buon segno, poiché significa che le variabili non sono fortemente correlate tra loro.

Valori VIF più elevati indicano una multicollinearità più forte, e valori al di sopra di una certa soglia (ad esempio, VIF > 5) possono suggerire la necessità di affrontare la collinearità, ad esempio, rimuovendo una delle variabili predittive correlate.

[Torna all’ Indice]

Punti Influenti

I punti influenti si riferiscono a osservazioni nei dati che hanno un impatto significativo sui risultati di un’analisi statistica, come una regressione lineare. Questi punti possono influenzare la stima dei parametri del modello, i residui, i valori p, l’R-squared e altre statistiche di rilevanza. Ci sono diverse metriche utilizzate per identificare i punti influenti, tra cui Standardized Residuals, Studentized Residuals e Cook’s Distance.

  • Standardized Residuals (Residui Standardizzati): Questi sono i residui divisi per la deviazione standard dei residui. Un residuo standardizzato è una misura di quanto un punto dato si discosti dalla linea di regressione in termini di deviazioni standard. I punti con residui standardizzati molto grandi (positivi o negativi) sono considerati influenti.
  • Studentized Residuals (Residui Studentizzati): Questi sono i residui divisi per una stima della deviazione standard dell’errore residuo. I residui studentizzati sono utilizzati per valutare quanto un punto dato sia influente considerando l’effetto delle altre osservazioni nel dataset. I punti con residui studentizzati significativamente grandi in valore assoluto sono considerati influenti.
  • Cook’s Distance (Distanza di Cook): Cook’s Distance è una metrica che combina l’effetto di un punto sui parametri del modello e il suo effetto sui residui. I punti con Cook’s Distance molto grandi sono considerati influenti. Cook’s Distance è spesso utilizzato per identificare punti che, se rimossi, avrebbero un impatto significativo sui risultati del modello.

Nel contesto della regressione, i punti influenti possono derivare da outlier nei dati, dati errati o punti che influenzano notevolmente la stima dei parametri. Identificare e trattare i punti influenti è importante per garantire che il modello di regressione sia affidabile e rappresenti accuratamente i dati. La rimozione di punti influenti può migliorare la bontà di adattamento del modello e l’accuratezza delle previsioni.

# Carichiamo il dataset di esempio
data(mtcars)

# Adattiamo un modello di regressione lineare
model <- lm(mpg ~ wt + hp, data = mtcars)

# Calcoliamo i residui standardizzati
standardized_residuals <- rstandard(model)

# Identifichiamo i punti influenti basati sui residui standardizzati
influential_points <- which(abs(standardized_residuals) > 2)

# Visualizziamo gli indici dei punti influenti
cat("Punti influenti basati sui residui standardizzati:", influential_points, "\n")
Punti influenti basati sui residui standardizzati: 17 18 20 
# Calcoliamo Cook's Distance
cook_distance <- cooks.distance(model)

# Identifichiamo i punti influenti basati su Cook's Distance
influential_points_cook <- which(cook_distance > 4 / length(cook_distance))

# Visualizziamo gli indici dei punti influenti basati su Cook's Distance
cat("Punti influenti basati su Cook's Distance:", influential_points_cook, "\n")
Punti influenti basati su Cook's Distance: 17 18 20 31 
par(mfrow = c(1,2))
# Grafico dei punti con evidenziazione dei punti influenti
plot(mtcars$wt, mtcars$mpg, pch = 16, main = "Scatter plot con Punti Influenti (Stan e Stud)",
     xlab = "Peso (wt)", ylab = "Miglia per gallone (mpg)")
points(mtcars$wt[influential_points], mtcars$mpg[influential_points], pch = 16, col = "red", cex = 1.5)


plot(mtcars$wt, mtcars$mpg, pch = 16, main = "Scatter plot con Punti Influenti (Cook)",
     xlab = "Peso (wt)", ylab = "Miglia per gallone (mpg)")
points(mtcars$wt[influential_points_cook], mtcars$mpg[influential_points_cook], pch = 16, col = "red", cex = 1.5)

Leverage:

Il “Leverage” è una misura utilizzata nell’analisi dei dati statistici per identificare punti influenti o osservazioni atipiche in un modello di regressione. Questa misura valuta quanto un’osservazione può influenzare i risultati del modello, in particolare i coefficienti di regressione. Il leverage è calcolato sulla base delle variabili predittive e può essere utilizzato per identificare le osservazioni che hanno un impatto significativo sul modello.

Identificazione dei punti influenti: I punti con un valore di leverage significativamente più alto degli altri sono quelli che possono influenzare notevolmente il modello. Puoi stabilire una soglia arbitraria o utilizzare metodi statistici per determinare quali punti sono influenti. Ad esempio, i punti con leverage superiore a 2 volte la media possono essere considerati influenti.

Esame dei punti influenti: Una volta identificati i punti influenti, è possibile esaminarli ulteriormente per determinare se sono effettivamente outliers o errori di misurazione. Potresti voler esaminare le osservazioni con elevate differenze tra i valori osservati e quelli previsti dal modello.

È importante notare che la rimozione dei punti influenti dovrebbe essere effettuata con cautela e solo se c’è una giustificazione valida. In alcuni casi, potresti scegliere di mantenere i punti influenti nel modello se ritieni che rappresentino informazioni significative o se hanno una spiegazione plausibile.

# Generiamo dati casuali
set.seed(123)
n <- 100
x <- rnorm(n)
y <- 2 * x + rnorm(n)

# Adattiamo un modello di regressione lineare
model <- lm(y ~ x)

# Calcoliamo i valori di leverage
leverage <- hatvalues(model)

# Identifichiamo i punti influenti
infl_points <- which(leverage > 2 * mean(leverage))

# Visualizziamo i punti influenti
print(infl_points)
 6 16 18 26 44 57 70 72 97 
 6 16 18 26 44 57 70 72 97 
par(mfrow = c(1,2))
# Plot del grafico
plot(x, y)
points(x[infl_points], y[infl_points], col = "blue", pch = 19)

# Plot del Leverage
plot(x, leverage)
points(x[infl_points], leverage[infl_points], col = "blue", pch = 19)

Nota che nell’esempio abbiamo utilizzato una soglia di leverage arbitraria (2 volte la media) per identificare i punti influenti. In un’applicazione pratica, è consigliabile considerare la soglia in base al contesto del problema e all’analisi dei dati.

[Torna all’ Indice]

Modelli Lineari Generalizzati

I GLM estendono il framework della regressione lineare per gestire un’ampia gamma di distribuzioni dei dati e tipologie di risposte. A differenza della regressione lineare tradizionale, i GLM possono accomodare distribuzioni di errori non normali e modellare relazioni tra predittori e risposte attraverso una funzione di collegamento.

Un GLM è caratterizzato da tre componenti principali:

  1. Componente Casuale (Distribuzione): La variabile di risposta \(Y\) segue una distribuzione di probabilità dalla famiglia esponenziale, che include distribuzioni comuni come normale, binomiale e di Poisson.

  2. Componente Sistematica (Predittore Lineare): La relazione tra i predittori e il valore atteso della risposta è espressa attraverso un predittore lineare (\(\eta\)). Il predittore lineare è una combinazione dei predittori, ognuno moltiplicato per un parametro, e si collega alla media della risposta attraverso una funzione di collegamento.

  3. Funzione di Collegamento: La funzione di collegamento (\(g(\mu)\)) stabilisce il collegamento tra il predittore lineare e la media della risposta. Trasforma la scala della variabile di risposta e assicura che il predittore lineare copra l’intera linea reale. Le funzioni di collegamento comuni includono logit, probit e identità.

La forma generale di un GLM può essere rappresentata come segue:

\[ g(\mu) = X\beta \]

Dove:

Esempi:

  1. Regressione Logistica Binaria:

    • Distribuzione: Binomiale
    • Funzione di Collegamento: Logit (log-rapporti di probabilità)
    • Equazione: \(\text{logit}(\mu) = X\beta\)

    Descrizione: La funzione di collegamento logit trasforma la probabilità di successo (\(\mu\)) in un predittore lineare. In questo caso, il modello logistic descrive come la log-odds della probabilità di successo sia lineare rispetto ai predittori.

  2. Regressione di Poisson:

    • Distribuzione: Poisson
    • Funzione di Collegamento: Log
    • Equazione: \(\log(\mu) = X\beta\)

    Descrizione: Con la funzione di collegamento logaritmico, il modello di Poisson può gestire dati di conteggio, poiché connette il logaritmo naturale del valore atteso (\(\mu\)) a un predittore lineare.

  3. Regressione Gamma:

    • Distribuzione: Gamma
    • Funzione di Collegamento: Inverso
    • Equazione: \(\frac{1}{\mu} = X\beta\)

    Descrizione: La funzione di collegamento inversa in un modello gamma è appropriata quando si modellano variabili con distribuzioni a coda pesante. Collega l’inverso del valore atteso (\(\mu\)) a un predittore lineare.

Devianza

La devianza è una misura della discrepanza tra il modello statistico e i dati osservati nei GLM. In generale, la devianza è utilizzata per confrontare modelli alternativi e valutare quanto bene un modello si adatta ai dati. Nel contesto dei GLM, la devianza è particolarmente significativa perché tiene conto delle specifiche distribuzioni delle variabili di risposta.

La devianza si calcola confrontando il modello fitted (previsto) con un modello null, spesso noto come modello null di saturazione. Il modello null rappresenta l’ipotesi che tutti i parametri del modello siano uguali a zero, indicando l’assenza di effetti predittori. La devianza è data dalla seguente formula:

\[ D = 2 \times \left( \ell(\hat{\beta}) - \ell(\beta_0) \right) \]

Dove:

  • \(\ell(\hat{\beta})\) è il log-likelihood del modello fitted.
  • \(\ell(\beta_0)\) è il log-likelihood del modello null.
  • \(D\) è la devianza.

Poiché i GLM utilizzano la famiglia esponenziale di distribuzioni, la devianza assume una forma specifica per diverse distribuzioni.

Formule della Verosimiglianza:

  1. Modello Normale: La verosimiglianza nel caso di una distribuzione normale è definita dalla densità di probabilità della distribuzione normale. Per una singola osservazione, la formula è: \[ L(y_i | \mu_i, \sigma^2) = \frac{1}{\sqrt{2\pi\sigma^2}} \exp\left(-\frac{(y_i - \mu_i)^2}{2\sigma^2}\right) \]

    Dove:

    • \(y_i\) è l’osservazione i-esima.
    • \(\mu_i\) è il valore atteso della variabile di risposta i-esima.
    • \(\sigma^2\) è la varianza.
  2. Modello di Poisson: La verosimiglianza nel caso di una distribuzione di Poisson è definita come segue: \[ L(y_i | \lambda_i) = \frac{\lambda_i^{y_i} \exp(-\lambda_i)}{y_i!} \]

    Dove:

    • \(y_i\) è l’osservazione i-esima.
    • \(\lambda_i\) è il valore atteso della variabile di risposta i-esima.

Interpretazione: La devianza può essere interpretata come una misura della discrepanza tra il modello fitted e il modello null. Un valore di devianza più basso indica una migliore adattabilità del modello ai dati. Tuttavia, poiché la devianza è una misura assoluta, è spesso utilizzato il concetto di devianza residua, che è la devianza divisa per il numero di gradi di libertà del modello. Questo consente un confronto più equo tra modelli con differenti complessità.

Contributo delle Componenti: Nel contesto dei GLM, la devianza è spesso scomposta in tre componenti principali:

  1. Modello Fitted Deviance (\(D_{\text{fitted}}\)): Misura la discrepanza tra il modello fitted e i dati osservati.

  2. Null Deviance (\(D_{\text{null}}\)): Misura la discrepanza tra il modello null e i dati osservati.

  3. Residual Deviance (\(D_{\text{residual}}\)): Rappresenta la devianza residua, cioè la discrepanza non spiegata dal modello fitted.

L’utilizzo di queste componenti permette di comprendere come la devianza è distribuita tra il modello fitted, il modello null e la devianza residua.

Confronto tra Modelli: Il test di devianza è spesso utilizzato per confrontare modelli alternativi. La differenza nella devianza tra due modelli segue approssimativamente una distribuzione chi-quadro sotto l’ipotesi nulla che i due modelli siano equivalenti. Questo test può essere utilizzato per valutare l’aggiunta di predittori al modello o per confrontare modelli con differenti specifiche di distribuzione della risposta.

Esempio di Devianza:

# Carichiamo un dataset di esempio in R
data(mtcars)

# Creiamo un modello di Poisson
model_poisson <- glm(vs ~ wt + hp, family = poisson, data = mtcars)

# Calcoliamo la devianza
deviance_value <- deviance(model_poisson)

cat("Devianza del Modello di Poisson:", deviance_value, "\n")
Devianza del Modello di Poisson: 9.969627 

In questo esempio, calcoliamo e visualizziamo la devianza residua di un modello di Poisson.

Residui

Funzione dei Residui nei GLM: Nei Modelli Lineari Generalizzati (GLM), i residui svolgono un ruolo cruciale nel valutare l’adattamento del modello ai dati e nel verificare la validità delle ipotesi dietro il modello. A differenza dei Modelli Lineari (LM), i residui nei GLM sono calcolati considerando la distribuzione della risposta specifica del modello.

  1. Misurare la Bontà di Adattamento:
    • I residui nei GLM sono utilizzati per valutare la bontà di adattamento del modello. Se il modello si adatta bene ai dati, ci si aspetta che i residui abbiano una distribuzione che riflette la distribuzione della risposta specificata nel GLM.
  2. Indicazioni sulla Struttura dei Dati:
    • Nei GLM, la scelta della distribuzione della risposta e della funzione di legame può variare in base alla natura dei dati. I residui forniscono indicazioni sulla struttura dei dati e sulla validità delle ipotesi del modello.
  3. Diagnosticare Devianza:
    • La devianza, una misura della differenza tra il modello completo e uno più semplice, può essere diagnosticata attraverso i residui. Residui devianti e standardized deviance residuals sono spesso utilizzati per individuare modelli non adatti ai dati.

Differenze tra Residui nei GLM e nei LM: Le principali differenze tra i residui nei GLM e nei LM riguardano la distribuzione della risposta e la funzione di legame.

  1. Distribuzione della Risposta:
    • Nei GLM, i residui sono calcolati tenendo conto della distribuzione della risposta specificata nel modello. Ad esempio, nei modelli di Poisson, i residui devono adattarsi alla distribuzione di Poisson.
    • Nei LM, i residui sono basati sull’assunzione che la risposta sia distribuita normalmente.
  2. Funzione di Legame:
    • La funzione di legame nei GLM determina come il valore atteso della risposta è collegato alla combinazione lineare dei predittori. La scelta della funzione di legame influenza i residui.
    • Nei LM, la funzione di legame è identità, e i residui riflettono semplicemente la differenza tra i valori osservati e quelli previsti.

Esempio di Calcolo dei Residui in un Modello GLM:

suppressWarnings({
# Carichiamo un dataset di esempio in R con una distribuzione di Poisson
data(faithful, package = "datasets")

# Creiamo un modello di Poisson
modello_poisson <- glm(eruptions ~ waiting, family = poisson, data = faithful)

# Calcoliamo i residui devianti
residui_devianti <- residuals(modello_poisson, type = "deviance")

# Visualizziamo i primi 10 residui devianti
head(residui_devianti)
})
         1          2          3          4          5          6 
-0.2147663 -0.2970575 -0.1293332 -0.2561309 -0.0479040  0.3822210 

Analisi dei Residui: I residui devianti riflettono le differenze tra i valori osservati e quelli previsti in termini della devianza del modello. Un residuo deviante elevato indica che l’osservazione contribuisce in modo significativo alla devianza complessiva del modello, indicando un’eventuale influenza o deviazione dal modello.

  • Residui positivi indicano che l’osservazione ha contribuito più del previsto alla devianza.
  • Residui negativi indicano che l’osservazione ha contribuito meno del previsto alla devianza.
  • Residui pari a zero indicano una perfetta adattabilità dell’osservazione al modello.

Esempio

Per questo esempio, useremo il dataset di esempio “mtcars” di R per creare un modello di Poisson utilizzando un modello generalizzato lineare (GLM). Lo scopo del modello sarà prevedere il numero di cilindri (“cyl”) in base alle altre variabili presenti nel dataset.

# Caricamento del dataset "mtcars"
data(mtcars)

# Esploriamo le prime righe del dataset
head(mtcars)

# Creiamo un modello di Poisson per prevedere il numero di cilindri in base alle altre variabili
modello_glm <- glm(cyl ~ mpg + disp + hp + drat + wt + qsec + vs + am + gear + carb, 
                   data = mtcars, family = poisson)

# Visualizziamo il summary del modello
summary(modello_glm)

Call:
glm(formula = cyl ~ mpg + disp + hp + drat + wt + qsec + vs + 
    am + gear + carb, family = poisson, data = mtcars)

Deviance Residuals: 
     Min        1Q    Median        3Q       Max  
-0.42777  -0.16289   0.01851   0.15996   0.40340  

Coefficients:
              Estimate Std. Error z value Pr(>|z|)
(Intercept)  3.1253653  2.3664672   1.321    0.187
mpg         -0.0058390  0.0351590  -0.166    0.868
disp         0.0006115  0.0025727   0.238    0.812
hp           0.0002488  0.0033108   0.075    0.940
drat        -0.0981988  0.2466800  -0.398    0.691
wt          -0.0366284  0.3070279  -0.119    0.905
qsec        -0.0406992  0.1219151  -0.334    0.739
vs          -0.1092921  0.3282386  -0.333    0.739
am          -0.1126824  0.3368595  -0.335    0.738
gear        -0.0517634  0.2304110  -0.225    0.822
carb         0.0280157  0.1270379   0.221    0.825

(Dispersion parameter for poisson family taken to be 1)

    Null deviance: 16.574  on 31  degrees of freedom
Residual deviance:  1.310  on 21  degrees of freedom
AIC: 139.97

Number of Fisher Scoring iterations: 4
# Analizziamo le variabili indipendenti
par(mfrow = c(2, 2))
plot(modello_glm)


# Eseguiamo l'analisi della varianza (ANOVA)
anova_result <- anova(modello_glm, test = "Chi")

# Visualizziamo la tabella ANOVA
print(anova_result)
Analysis of Deviance Table

Model: poisson, link: log

Response: cyl

Terms added sequentially (first to last)

     Df Deviance Resid. Df Resid. Dev  Pr(>Chi)    
NULL                    31    16.5743              
mpg   1  12.2921        30     4.2822 0.0004549 ***
disp  1   1.1779        29     3.1043 0.2777770    
hp    1   0.3231        28     2.7812 0.5697385    
drat  1   0.3586        27     2.4225 0.5492712    
wt    1   0.2091        26     2.2135 0.6475086    
qsec  1   0.4558        25     1.7577 0.4996039    
vs    1   0.1329        24     1.6248 0.7154335    
am    1   0.2440        23     1.3808 0.6213230    
gear  1   0.0221        22     1.3587 0.8817565    
carb  1   0.0487        21     1.3100 0.8253848    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
# Calcoliamo l'R-squared del modello
r_squared <- 1 - (modello_glm$deviance / modello_glm$null.deviance)
cat("R-squared:", r_squared, "\n")
R-squared: 0.9209632 
# Effettuiamo previsioni su nuovi dati (per esempio, le prime 5 osservazioni del dataset)
nuovi_dati <- mtcars[1:5, ]
previsioni <- predict(modello_glm, newdata = nuovi_dati, type = "response")
cat("Previsioni per le prime 5 osservazioni:\n", previsioni, "\n")
Previsioni per le prime 5 osservazioni:
 5.879263 5.693355 4.305739 5.683563 7.787923 

In questo esempio, abbiamo creato un modello di Poisson utilizzando il numero di cilindri come variabile dipendente e le altre variabili del dataset “mtcars” come variabili indipendenti. Successivamente, abbiamo eseguito un’analisi completa del modello, compresi il summary, la visualizzazione delle variabili indipendenti, l’analisi della varianza (ANOVA), il calcolo dell’R-squared e la previsione su nuovi dati.

[[Torna all’ Indice]]

LS0tCnRpdGxlOiAiUmlhc3N1bnRvIEFuYWxpc2kgUHJlZGl0dGl2YSIKb3V0cHV0OiBodG1sX25vdGVib29rCmF1dGhvcjogIlNpbW9uZSBEaW5hdG8iCmRhdGU6ICJEYXRhIGRpIENyZWF6aW9uZTogMjAyMy0xMC0yMCIKdmVyc2lvbjogIlZlcnNpb25lOiAwLjgiCmVkaXRvcl9vcHRpb25zOiAKICBtYXJrZG93bjogCiAgICB3cmFwOiBzZW50ZW5jZQotLS0KCiMgSW50cm9kdXppb25lCgpRdWVzdG8gZG9jdW1lbnRvIGZvcm5pc2NlIHVuJ2FtcGlhIHBhbm9yYW1pY2Egc3VsIGNvcnNvIGRpIEFuYWxpc2kgUHJlZGl0dGl2YSBkaSBDYScgRm9zY2FyaSAoQ1QwNDI5KSBkZWxsJ2Fubm8gMjAyMy8yMDI0LgpOZWwgY29yc28gZGVsIGRvY3VtZW50bywgZXNwbG9yZXJlbW8gdmFyaSBhcmdvbWVudGkgcmlndWFyZGFudGkgbCdBbmFsaXNpIFByZWRpdHRpdmEsIGNvbXByZXNpIEFub3ZhLCBSZXNpZHVpLCBGb3JtdWxlLCBDb3JyZWxhemlvbmUgdHJhIHZhcmlhYmlsaSwgUHJlZGljdCwgbCd1dGlsaXp6byBkaSBwacO5IG1vZGVsbGksIGUgY29tZSBzZWxlemlvbmFyZSBsZSB2YXJpYWJpbGkgYWxsJ2ludGVybm8gZGkgdW4gbW9kZWxsby4KCkwnb2JpZXR0aXZvIGRpIHF1ZXN0byBkb2N1bWVudG8gw6ggZ3VpZGFydGkgYXR0cmF2ZXJzbyBpIGNvbmNldHRpIGNoaWF2ZSBlIGxlIHByYXRpY2hlIG5lbGwnQW5hbGlzaSBQcmVkaXR0aXZhLCBjb24gdW4gZm9jdXMgc3VsbCd1dGlsaXp6byBkZWwgbGluZ3VhZ2dpbyBkaSBwcm9ncmFtbWF6aW9uZSBSIHBlciBhcHBsaWNhcmUgcXVlc3RlIHRlY25pY2hlLgpTcGVybyBjaGUgcXVlc3RvIGRvY3VtZW50byB0aSBhaXV0aSBhIGNvbXByZW5kZXJlIG1lZ2xpbyBxdWVzdGEgbWF0ZXJpYSBkaSBzdHVkaW8gYWwgZmluZSBkaSBzdXBlcmFyZSBsJ2VzYW1lLgoKIyMjIEluZGljZQoKLSAgIFtSZWdyZXNzaW9uZSBMaW5lYXJlXQogICAgLSAgIFtBbmFsaXNpIGRlaSByZXNpZHVpXQogICAgLSAgIFtTY29tcG9zaXppb25lIFNvbW1hIERpIFF1YWRyYXRpXQogICAgLSAgIFtQcmVkaXppb25lIE90dGltYWxlXQogICAgLSAgIFtDb3ZhcmlhbnphIGUgQ29ycmVsYXppb25lIEVtcGlyaWNhXQotICAgW1JlZ3Jlc3Npb25lIExpbmVhcmUgTXVsdGlwbGFdCiAgICAtICAgW0FwcHJvY2lvIE1hdHJpY2lhbGVdCiAgICAtICAgW0ludGVycHJldGF6aW9uZSBHZW9tZXRyaWNhXQogICAgLSAgIFtEaXN0cmlidXppb25lIEYgJiBBbm92YSBUYWJsZV0KICAgIC0gICBbTW9kZWxsaSBOaWRpZmljYXRpXQogICAgLSAgIFtTZWxlemlvbmUgZGVsbGUgdmFyaWFiaWxpXQogICAgLSAgIFtQcmVkaXppb25pIENhdGVnb3JpY2hlXQogICAgLSAgIFtDb250cm9sbG8gZGVsIE1vZGVsbG9dCiAgICAtICAgW1RyYW5zZm9ybWF6aW9uaV0KICAgIC0gICBbTXVsdGljb2xsaW5lYXJpdMOgXQogICAgLSAgIFtQdW50aSBJbmZsdWVudGldCi0gICBbTW9kZWxsaSBMaW5lYXJpIEdlbmVyYWxpenphdGldCiAgICAtICAgW0RldmlhbnphXQogICAgLSAgIFtSZXNpZHVpXQoKIyBSZWdyZXNzaW9uZSBMaW5lYXJlCgpMYSBSZWdyZXNzaW9uZSBMaW5lYXJlIChMUikgw6ggdW5hIHRlY25pY2Egc3RhdGlzdGljYSBjaGUgdmllbmUgdXRpbGl6emF0YSBwZXIgc3R1ZGlhcmUgbGEgcmVsYXppb25lIHRyYSBkdWUgbyBwacO5IHZhcmlhYmlsaSBxdWFudGl0YXRpdmUuIElsIG1vZGVsbG8gZGkgcmVncmVzc2lvbmUgbGluZWFyZSBhc3N1bWUgY2hlIGxhIHZhcmlhYmlsZSBkaXBlbmRlbnRlLCBjaGUgc2kgZGVzaWRlcmEgcHJlZGlyZSwgc2lhIHVuYSBmdW56aW9uZSBsaW5lYXJlIGRlbGxlIHZhcmlhYmlsaSBpbmRpcGVuZGVudGkuCgpJbCBtb2RlbGxvIGRpIHJlZ3Jlc3Npb25lIGxpbmVhcmUgZmEgbGUgc2VndWVudGkgYXNzdW56aW9uaToKCiogKipMaW5lYXJpdMOgOioqIExhIHJlbGF6aW9uZSB0cmEgbGEgdmFyaWFiaWxlIGRpcGVuZGVudGUgZSBsZSB2YXJpYWJpbGkgaW5kaXBlbmRlbnRpIMOoIGxpbmVhcmUuCiogKipOb3JtYWxpdMOgOioqIEkgcmVzaWR1aSBzb25vIGRpc3RyaWJ1aXRpIG5vcm1hbG1lbnRlLgoqICoqSW5kaXBlbmRlbnphOioqIEkgcmVzaWR1aSBzb25vIGluZGlwZW5kZW50aSB0cmEgbG9yby4KKiAqKkV0ZXJvc2NoZWRhc3RpY2l0w6A6KiogTGEgdmFyaWFuemEgZGVpIHJlc2lkdWkgw6ggY29zdGFudGUuCgpMJ2VxdWF6aW9uZSBkZWwgbW9kZWxsbyBkaSByZWdyZXNzaW9uZSBsaW5lYXJlIHNlbXBsaWNlIMOoIGxhIHNlZ3VlbnRlOgoKCiQkIHkgPSBhICsgYnggJCQKCgpkb3ZlOgoKKiB5IMOoIGxhIHZhcmlhYmlsZSBkaXBlbmRlbnRlCiogYSDDqCBsJ2ludGVyY2V0dGEKKiBiIMOoIGlsIGNvZWZmaWNpZW50ZSBhbmdvbGFyZQoqIHggw6ggbGEgdmFyaWFiaWxlIGluZGlwZW5kZW50ZQoKTCdpbnRlcmNldHRhIHJhcHByZXNlbnRhIGlsIHZhbG9yZSBtZWRpbyBkaSB5IHF1YW5kbyB4IMOoIHVndWFsZSBhIDAuIElsIGNvZWZmaWNpZW50ZSBhbmdvbGFyZSByYXBwcmVzZW50YSBsYSB2YXJpYXppb25lIGRpIHkgcGVyIG9nbmkgdW5pdMOgIGRpIHZhcmlhemlvbmUgZGkgeC4KCiMjIyBBbmFsaXNpIGRlaSByZXNpZHVpCgpTZXJ2ZSBhIHZlcmlmaWNhcmUgc2UgaWwgbW9kZWxsbyBzb2RkaXNmYSBsZSBhc3N1bnppb25pIGRlbGxhIHJlZ3Jlc3Npb25lIGUgcGVyIGlkZW50aWZpY2FyZSBldmVudHVhbGkgcGF0dGVybiBvIHByb2JsZW1pIG5laSBkYXRpLgoKKipFc2VtcGlvIDE6KioKCmBgYHtyfQojIEdlbmVyaWFtbyBkYXRpIGNhc3VhbGkgY29uIHJlc2lkdWkgbm9ybWFsbWVudGUgZGlzdHJpYnVpdGkKc2V0LnNlZWQoMTIzKQp4IDwtIDE6MTAwCnkgPC0gMiAqIHggKyBybm9ybSgxMDApCgojIEFkYXR0aWFtbyB1biBtb2RlbGxvIGRpIHJlZ3Jlc3Npb25lCm1vZGVsIDwtIGxtKHkgfiB4KQoKIyBFZmZldHR1aWFtbyBsJ2FuYWxpc2kgZGVpIHJlc2lkdWkKUmVzaWR1YWxzIDwtIHJlc2lkdWFscyhtb2RlbCkKCiMgQ3JlaWFtbyB1biBncmFmaWNvIGRlaSByZXNpZHVpCnBsb3QoeCwgUmVzaWR1YWxzLCBtYWluID0gIkRpc3RyaWJ1emlvbmUgTm9ybWFsZSBkZWkgUmVzaWR1aSIseGxhYiA9ICJYIiwgeWxhYiA9ICJSZXNpZHVpIikKYWJsaW5lKGggPSAwLCBjb2wgPSAicmVkIikKYGBgCgpJbiBxdWVzdG8gY2FzbywgaSByZXNpZHVpIHNlZ3Vvbm8gdW5hIGRpc3RyaWJ1emlvbmUgbm9ybWFsZSwgaWwgY2hlIMOoIHVuIHJpc3VsdGF0byBpZGVhbGUgcGVyIHVuIG1vZGVsbG8gZGkgcmVncmVzc2lvbmUgbGluZWFyZS4KUXVhbmRvIGRpY2lhbW8gY2hlIGkgcmVzaWR1aSBoYW5ubyB1bmEgZGlzdHJpYnV6aW9uZSBub3JtYWxlLCBzaWduaWZpY2EgY2hlIGkgcmVzaWR1aSBzZWd1b25vIHVuYSBkaXN0cmlidXppb25lIGEgZm9ybWEgZGkgY2FtcGFuYSwgY29uIHVuYSBtZWRpYSBkaSB6ZXJvIGUgdW5hIHZhcmlhbnphIGNvc3RhbnRlLgpRdWVzdGEgw6ggdW4naW1wb3J0YW50ZSBhc3N1bnppb25lIG5laSBtb2RlbGxpIGRpIHJlZ3Jlc3Npb25lIGxpbmVhcmUsIGluIHF1YW50byBpbmRpY2EgY2hlIGdsaSBlcnJvcmkgY2FzdWFsaSBuZWwgbW9kZWxsbyBzb25vIGRpc3RyaWJ1aXRpIGluIG1vZG8gc2ltbWV0cmljbyBpbnRvcm5vIGEgemVybyBlIG5vbiBtb3N0cmFubyBhbGN1biB0aXBvIGRpIHRlbmRlbnphIHNpc3RlbWljYS4KU2UgcXVlc3RhIGFzc3VuemlvbmUgw6ggc29kZGlzZmF0dGEsIGkgdGVzdCBkaSBzaWduaWZpY2F0aXZpdMOgIGRlaSBjb2VmZmljaWVudGkgZGVsIG1vZGVsbG8gZSBsZSBzdGltZSBkaSBpbnRlcnZhbGxvIGRpIGNvbmZpZGVuemEgc2FyYW5ubyBhZmZpZGFiaWxpLgoKKipFc2VtcGlvIDI6KioKCmBgYHtyfQojIEdlbmVyaWFtbyBkYXRpIGNhc3VhbGkgY29uIHJlc2lkdWkgY2hlIHNlZ3Vvbm8gdW5hIGRpc3RyaWJ1emlvbmUgYSBVCnNldC5zZWVkKDQ1NikKeCA8LSAxOjEwMAp5IDwtIDIgKiB4XjIgKyBybm9ybSgxMDApCnlbNTA6NjBdIDwtIHlbNTA6NjBdICsgMTAgICMgSW50cm9kdWNpYW1vIHVuIGVmZmV0dG8gYSBVIG5laSBkYXRpCgojIEFkYXR0aWFtbyB1biBtb2RlbGxvIGRpIHJlZ3Jlc3Npb25lCm1vZGVsIDwtIGxtKHkgfiB4KQoKIyBFZmZldHR1aWFtbyBsJ2FuYWxpc2kgZGVpIHJlc2lkdWkKcmVzaWR1YWxzIDwtIHJlc2lkdWFscyhtb2RlbCkKCiMgQ3JlaWFtbyB1biBncmFmaWNvIGRlaSByZXNpZHVpCnBsb3QoeCwgcmVzaWR1YWxzLCBtYWluID0gIkRpc3RyaWJ1emlvbmUgYSBVIGRlaSBSZXNpZHVpIiwgeGxhYiA9ICJYIiwgeWxhYiA9ICJSZXNpZHVpIikKYWJsaW5lKGggPSAwLCBjb2wgPSAicmVkIikKYGBgCgpJbiBxdWVzdG8gY2FzbywgaSByZXNpZHVpIG1vc3RyYW5vIHVuIGVmZmV0dG8gYSBVLCBpbmRpY2FuZG8gdW5hIHZpb2xhemlvbmUgZGVsbCdhc3N1bnppb25lIGRpIG9tb3NjaGVkYXN0aWNpdMOgKGkgcmVzaWR1aSBub24gbW9zdHJhbm8gdW4gYXVtZW50byBvIHVuYSBkaW1pbnV6aW9uZSBzaXN0ZW1hdGljYSBuZWxsYSBkaXNwZXJzaW9uZSBhbCB2YXJpYXJlIGRlaSB2YWxvcmkgZGVsbGUgdmFyaWFiaWxpIGluZGlwZW5kZW50aSkuCgoqKkVzZW1waW8gMzoqKgoKYGBge3J9CiMgR2VuZXJpYW1vIGRhdGkgY2FzdWFsaSBjb24gb3V0bGllciBuZWkgcmVzaWR1aQpzZXQuc2VlZCg3ODkpCnggPC0gMToxMDAKeSA8LSAyICogeCArIHJub3JtKDEwMCkKeVtjKDIwLCA4NSldIDwtIHlbYygyMCwgODUpXSArIDIwICAjIEFnZ2l1bmdpYW1vIG91dGxpZXIgbmVpIGRhdGkKCiMgQWRhdHRpYW1vIHVuIG1vZGVsbG8gZGkgcmVncmVzc2lvbmUKbW9kZWwgPC0gbG0oeSB+IHgpCgojIEVmZmV0dHVpYW1vIGwnYW5hbGlzaSBkZWkgcmVzaWR1aQpyZXNpZHVhbHMgPC0gcmVzaWR1YWxzKG1vZGVsKQoKIyBDcmVpYW1vIHVuIGdyYWZpY28gZGVpIHJlc2lkdWkKcGxvdCh4LCByZXNpZHVhbHMsIG1haW4gPSAiUHJlc2VuemEgZGkgT3V0bGllciBuZWkgUmVzaWR1aSIsIHlsYWIgPSAiUmVzaWR1aSIsIHhsYWIgPSAiWCIpCmFibGluZShoID0gMCwgY29sID0gInJlZCIpCmBgYAoKSW4gcXVlc3RvIGNhc28sIGkgcmVzaWR1aSBtb3N0cmFubyBsYSBwcmVzZW56YSBkaSBvdXRsaWVyIGV2aWRlbnRpLCBjaGUgcG9zc29ubyBpbmZsdWVuemFyZSBpbiBtb2RvIHNpZ25pZmljYXRpdm8gbGEgc3RpbWEgZGVpIGNvZWZmaWNpZW50aSBkZWwgbW9kZWxsby4KR2xpIG91dGxpZXIgcG9zc29ubyBjb21wb3J0YXJlIHByb2JsZW1pIG5laSBtb2RlbGxpIHN0YXRpc3RpY2ksIHNwZWNpYWxtZW50ZSBuZWkgbW9kZWxsaSBkaSByZWdyZXNzaW9uZSwgcGVyY2jDqSBwb3Nzb25vIGluZmx1ZW56YXJlIG5vdGV2b2xtZW50ZSBpIHJpc3VsdGF0aS4KQWQgZXNlbXBpbywgcG9zc29ubyBpbmZsdWVuemFyZSBsYSBzdGltYSBkZWkgY29lZmZpY2llbnRpIGRlbCBtb2RlbGxvIGUgcmVuZGVyZSBpbCBtb2RlbGxvIG1lbm8gYWZmaWRhYmlsZS4KCltUb3JuYSBhbGwnIFtJbmRpY2VdXQoKIyMjIFNjb21wb3NpemlvbmUgU29tbWEgRGkgUXVhZHJhdGkKCkxhICJkZWNvbXBvc2l0aW9uIG9mIHN1bSBvZiBzcXVhcmVzIiDDqCB1biBjb25jZXR0byBmb25kYW1lbnRhbGUgbmVsbCdhbmFsaXNpIGRlbGxhIHZhcmlhbnphIChBTk9WQSkgZSBuZWxsYSByZWdyZXNzaW9uZSBzdGF0aXN0aWNhLgpRdWVzdGEgdGVjbmljYSBhaXV0YSBhIHNjb21wb3JyZSBsYSB2YXJpYW56YSB0b3RhbGUgb3NzZXJ2YXRhIGluIHVuIGluc2llbWUgZGkgZGF0aSBpbiBkaXZlcnNlIGNvbXBvbmVudGksIGNvbnNlbnRlbmRvIGRpIGNvbXByZW5kZXJlIHF1YW50byBkZWxsYSB2YXJpYW56YSBwdcOyIGVzc2VyZSBhdHRyaWJ1aXRvIGEgdmFyaSBmYXR0b3JpIG8gZXJyb3JpIHJlc2lkdWkuCkxhIGZvcm11bGEgY2hpYXZlIGluIHF1ZXN0byBjb250ZXN0byDDqDoKCiQkIFZhcmlhbnphIFRvdGFsZSA9IFZhcmlhbnphIFNwaWVnYXRhICsgVmFyaWFuemEgUmVzaWR1YSAkJAoKRG92ZToKCi0gICBWYXJpYW56YSBUb3RhbGUgw6ggbGEgdmFyaWFuemEgY29tcGxlc3NpdmEgZGVpIGRhdGksIGNpb8OoIHF1YW50byBpIGRhdGkgdmFyaWFubyBpbiBnZW5lcmFsZS4KCi0gICBWYXJpYW56YSBTcGllZ2F0YSByYXBwcmVzZW50YSBsYSB2YXJpYW56YSBkb3Z1dGEgYWwgbW9kZWxsbyBvIGFpIGZhdHRvcmkgZXNhbWluYXRpIChzcGllZ2F0aSBkYWxsYSB2YXJpYWJpbGUgaW5kaXBlbmRlbnRlIG5lbCBjb250ZXN0byBkZWxsYSByZWdyZXNzaW9uZSkuCgotICAgVmFyaWFuemEgUmVzaWR1YSDDqCBsYSB2YXJpYW56YSBub24gc3BpZWdhdGEgZGFsIG1vZGVsbG8gbyBkYWkgZmF0dG9yaSBlZCDDqCBhc3NvY2lhdGEgYWxsJ2Vycm9yZSByZXNpZHVvLCBvdnZlcm8gbGEgZGlmZmVyZW56YSB0cmEgaSB2YWxvcmkgb3NzZXJ2YXRpIGUgcXVlbGxpIHByZXZpc3RpIGRhbCBtb2RlbGxvLgoKTmVsIGNvbnRlc3RvIGRlbGxhIHJlZ3Jlc3Npb25lLCBwdW9pIHJhcHByZXNlbnRhcmUgbGEgZGVjb21wb3NpemlvbmUgZGVsbGEgc29tbWEgZGVpIHF1YWRyYXRpIGNvbWUgc2VndWU6CgokJCBTU1QgPSBTU1IgKyBTU0UgJCQKCi0gICBTU1QgKFN1bSBvZiBTcXVhcmVzIFRvdGFsKSByYXBwcmVzZW50YSBsYSBzb21tYSBkZWkgcXVhZHJhdGkgdG90YWxlIGVkIMOoIGxhIHZhcmlhbnphIGRlaSBkYXRpIG9zc2VydmF0aSByaXNwZXR0byBhbGxhIGxvcm8gbWVkaWEuCgotICAgU1NSIChTdW0gb2YgU3F1YXJlcyBSZWdyZXNzaW9uKSByYXBwcmVzZW50YSBsYSB2YXJpYW56YSBzcGllZ2F0YSBkYWwgbW9kZWxsbyBvIGRhbGxhIHZhcmlhYmlsZSBpbmRpcGVuZGVudGUuCgotICAgU1NFIChTdW0gb2YgU3F1YXJlcyBFcnJvcikgcmFwcHJlc2VudGEgbGEgdmFyaWFuemEgcmVzaWR1YSwgb3NzaWEgbGEgdmFyaWFuemEgbm9uIHNwaWVnYXRhIGRhbCBtb2RlbGxvLgoKUGVyIHZhbHV0YXJlIGwnZWZmaWNpZW56YSBkZWwgdHVvIG1vZGVsbG8gZGkgcmVncmVzc2lvbmUsIGRvdnJlc3RpIGd1YXJkYXJlIGxhIHByb3Bvcnppb25lIGRpIHF1ZXN0YSB2YXJpYW56YSBzcGllZ2F0YSBkYWwgdHVvIG1vZGVsbG8gKFNTUikuCkluIGdlbmVyYWxlLCB2dW9pIG1hc3NpbWl6emFyZSBsYSBwcm9wb3J6aW9uZSBzcGllZ2F0YSBlIG1pbmltaXp6YXJlIGxhIHByb3Bvcnppb25lIG5vbiBzcGllZ2F0YSAoU1NFKS4KUGVydGFudG8sIHB1bnRpIGEgbWluaW1penphcmUgU1NFLgoKYGBge3J9CmRhdGEgPC0gZGF0YS5mcmFtZShYID0gYygxLCAyLCAzLCA0LCA1KSwgWSA9IGMoMywgNSwgNiwgOCwgMTApKQptZWFuX1kgPC0gbWVhbihkYXRhJFkpClNTVCA8LSBzdW0oKGRhdGEkWSAtIG1lYW5fWSleMikKCiMgQWRhdHRhIGlsIG1vZGVsbG8gZGkgcmVncmVzc2lvbmUgbGluZWFyZQptb2RlbCA8LSBsbShZIH4gWCwgZGF0YSA9IGRhdGEpCgojIENhbGNvbGEgbGEgU1NSClNTUiA8LSBzdW0oKHByZWRpY3QobW9kZWwpIC0gbWVhbl9ZKV4yKQoKIyBDYWxjb2xhIGxhIFNTRQpTU0UgPC0gc3VtKG1vZGVsJHJlc2lkdWFsc14yKQoKUl9zcXVhcmVkIDwtIFNTUiAvIFNTVAoKIyBFcXVpdmFsZSBhIGZhcmUgc3VtbWFyeShtb2RlbCkKUl9zcXVhcmVkCmBgYAoKW1Rvcm5hIGFsbCcgW0luZGljZV1dCgojIyMgUHJlZGl6aW9uZSBPdHRpbWFsZQoKTCciT3B0aW1hbCBQcmVkaWN0aW9uIiAgcmlndWFyZGEgbGEgZGV0ZXJtaW5hemlvbmUgZGkgdW4gbW9kZWxsbyBwcmVkaXR0aXZvIGNoZSBzaWEgaWwgbWlnbGlvcmUgcG9zc2liaWxlIGluIHRlcm1pbmkgZGkgYWNjdXJhdGV6emEgbmVsIHByZXZlZGVyZSBnbGkgZXZlbnRpIGZ1dHVyaS4KCkwnb2JpZXR0aXZvIHByaW5jaXBhbGUgw6ggdHJvdmFyZSBpbCBtb2RlbGxvIGNoZSBtYXNzaW1penphIGxhIHByZWNpc2lvbmUgZGVsbGUgcHJldmlzaW9uaSwgbWluaW1penphbmRvIGwnZXJyb3JlIGRpIHByZXZpc2lvbmUuCkNpIHNvbm8gdmFyaSBtZXRvZGkgZSB0ZWNuaWNoZSBwZXIgb3R0ZW5lcmUgbGEgcHJlZGl6aW9uZSBvdHRpbWFsZSwgYSBzZWNvbmRhIGRlbCBjb250ZXN0byBlIGRlaSBkYXRpIGRpc3BvbmliaWxpLgoKYGBge3J9CiMgQ2FyaWNhbWVudG8gZGVsIGRhdGFzZXQgImNhcnMiCmRhdGEoY2FycykKCiMgVmlzdWFsaXp6YXppb25lIGRlbGxlIHByaW1lIHJpZ2hlIGRlbCBkYXRhc2V0CmhlYWQoY2FycykKCiMgRGl2aWRpYW1vIGlsIGRhdGFzZXQgaW4gc2V0IGRpIGFkZGVzdHJhbWVudG8gZSBzZXQgZGkgdGVzdApzZXQuc2VlZCgxMjMpICAjIEltcG9zdGlhbW8gdW4gc2VlZCBwZXIgbGEgcmlwcm9kdWNpYmlsaXTDoApzYW1wbGVfaW5kaWNlcyA8LSBzYW1wbGUobnJvdyhjYXJzKSwgbnJvdyhjYXJzKSAqIDAuNykgICMgNzAlIGRhdGkgZGkgYWRkZXN0cmFtZW50bwp0cmFpbl9kYXRhIDwtIGNhcnNbc2FtcGxlX2luZGljZXMsIF0KdGVzdF9kYXRhIDwtIGNhcnNbLXNhbXBsZV9pbmRpY2VzLCBdCgojIEFkYXR0YW1lbnRvIGRpIHVuIG1vZGVsbG8gZGkgcmVncmVzc2lvbmUgbGluZWFyZQptb2RlbCA8LSBsbShkaXN0IH4gc3BlZWQsIGRhdGEgPSB0cmFpbl9kYXRhKQoKIyBQcmVkaXppb25pCnByZWRpY3Rpb25zIDwtIHByZWRpY3QobW9kZWwsIG5ld2RhdGEgPSB0ZXN0X2RhdGEpCgojIFZhbHV0YXppb25lIGRlbGxlIHByZXN0YXppb25pCnN1bW1hcnkobW9kZWwpCgojIEdyYWZpY28gZGVpIHJpc3VsdGF0aQpsaWJyYXJ5KGdncGxvdDIpCmdncGxvdChkYXRhID0gdGVzdF9kYXRhLCBhZXMoeCA9IHNwZWVkLCB5ID0gZGlzdCkpICsKICBnZW9tX3BvaW50KGNvbG9yID0gImJsdWUiKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAicmVkIikgKwogIGdndGl0bGUoIlByZWRpemlvbmUgZGVsbGEgRGlzdGFuemEgZGkgQXJyZXN0byIpCgpgYGAKCltUb3JuYSBhbGwnIFtJbmRpY2VdXQoKIyMjIENvdmFyaWFuemEgZSBDb3JyZWxhemlvbmUgRW1waXJpY2EKCkxhIGNvdmFyaWFuemEgZSBjb3JyZWxhemlvbmUgZW1waXJpY2Egc29ubyBtaXN1cmUgc3RhdGlzdGljaGUgdXRpbGl6emF0ZSBwZXIgcXVhbnRpZmljYXJlIGxhIHJlbGF6aW9uZSB0cmEgZHVlIHZhcmlhYmlsaSBpbiB1biBpbnNpZW1lIGRpIGRhdGkgb3NzZXJ2YXRpLgpRdWVzdGUgbWlzdXJlIHNvbm8gc3RyZXR0YW1lbnRlIGxlZ2F0ZSBlIHNvbm8gc3Blc3NvIHV0aWxpenphdGUgcGVyIGVzYW1pbmFyZSBsYSByZWxhemlvbmUgbGluZWFyZSB0cmEgZHVlIHZhcmlhYmlsaS4KCioqQ292YXJpYW56YSBFbXBpcmljYToqKgoKTGEgY292YXJpYW56YSBlbXBpcmljYSDDqCB1bmEgbWlzdXJhIGRlbGxhIHRlbmRlbnphIGRpIGR1ZSB2YXJpYWJpbGkgYSB2YXJpYXJlIGluc2llbWUuCkluZGljYSBzZSBsZSBkdWUgdmFyaWFiaWxpIGNyZXNjb25vIG8gZGltaW51aXNjb25vIHNpbXVsdGFuZWFtZW50ZSAoY292YXJpYW56YSBwb3NpdGl2YSkgbyBzZSB1bmEgYXVtZW50YSBtZW50cmUgbCdhbHRyYSBkaW1pbnVpc2NlIChjb3ZhcmlhbnphIG5lZ2F0aXZhKS4KTGEgZm9ybXVsYSBwZXIgY2FsY29sYXJlIGxhIGNvdmFyaWFuemEgZW1waXJpY2EgdHJhIGR1ZSB2YXJpYWJpbGkgWCBlIFkgaW4gdW4gc2V0IGRpIGRhdGkgw6ggZGF0YSBkYToKCiQkICBDb3YoWCxZKSA9IFxmcmFjezF9e24tMX0gXHN1bV97aSA9IDF9Xm4geyhYX2kgLSBcb3ZlcmxpbmV7WH0pKFlfaSAtIFxvdmVybGluZXtZfSl9ICQkCgoqKkNvcnJlbGF6aW9uZSBFbXBpcmljYToqKgoKTGEgY29ycmVsYXppb25lIGVtcGlyaWNhIMOoIHVuYSB2ZXJzaW9uZSBzdGFuZGFyZGl6emF0YSBkZWxsYSBjb3ZhcmlhbnphIGVtcGlyaWNhIGUgbWlzdXJhIGxhIGZvcnphIGUgbGEgZGlyZXppb25lIGRpIHVuYSByZWxhemlvbmUgbGluZWFyZSB0cmEgZHVlIHZhcmlhYmlsaS4KTGEgY29ycmVsYXppb25lIGVtcGlyaWNhIMOoIHNlbXByZSBjb21wcmVzYSB0cmEgLTEgZSAxLgpMYSBmb3JtdWxhIHBlciBjYWxjb2xhcmUgbGEgY29ycmVsYXppb25lIGVtcGlyaWNhIHRyYSBkdWUgdmFyaWFiaWxpIFggZSBZIMOoIGRhdGEgZGE6CgokJCAgQ29yKFgsWSkgPSBcZnJhY3tDb3YoWCxZKX17U19YIFxjZG90IFNfWX0gJCQKCkxlIG1pc3VyZSBkaSBjb3ZhcmlhbnphIGVtcGlyaWNhIGUgY29ycmVsYXppb25lIGVtcGlyaWNhIHNvbm8gdXRpbGl6emF0ZSBwZXIgZXNhbWluYXJlIGxhIHJlbGF6aW9uZSB0cmEgdmFyaWFiaWxpIGluIHVuIHNldCBkaSBkYXRpIGUgc29ubyBwYXJ0aWNvbGFybWVudGUgdXRpbGkgbmVsbCdhbmFsaXNpIHN0YXRpc3RpY2EgZSBuZWxsJ2FwcHJlbmRpbWVudG8gYXV0b21hdGljbyBwZXIgdmFsdXRhcmUgbGUgYXNzb2NpYXppb25pIHRyYSBsZSB2YXJpYWJpbGkgcHJpbWEgZGkgY29zdHJ1aXJlIG1vZGVsbGkgcHJlZGl0dGl2aS4KTGEgY29ycmVsYXppb25lIGVtcGlyaWNhIMOoIHBpw7kgY29tdW5lbWVudGUgdXRpbGl6emF0YSBwZXJjaMOpIGZvcm5pc2NlIHVuYSBtaXN1cmEgc3RhbmRhcmRpenphdGEgZGVsbGEgcmVsYXppb25lIHRyYSB2YXJpYWJpbGkgZWQgw6ggbWVubyBpbmZsdWVuemF0YSBkYWxsJ3VuaXTDoCBkaSBtaXN1cmEuCgpJbCBjb2VmZmljaWVudGUgZGkgUGVhcnNvbiDDqCB1dGlsZSBwZXIgdmVkZXJlIHNlIGR1ZSB2YXJpYWJpbGkgaGFubm8gdW5hIGNvcnJlbGF6aW9uZSBsaW5lYXJlIG8gbWVuby4KUXVlc3RvIHBlcmNow6kgbm9uIHR1dHRlIGxlIHZhcmlhYmlsaSBjb3JyZWxhdGUgaGFubm8gdW5hIHJlbGF6aW9uZSBsaW5lYXJlLgoKRXNlbXBpbzoKCmBgYHtyfQojIEVzZW1waW8gZGF0aSBjYXN1YWxpCnNldC5zZWVkKDEyMykKeCA8LSBybm9ybSgxMDApICAjIFZhcmlhYmlsZSB4CnkgPC0gMiAqIHggKyBybm9ybSgxMDApICAjIFZhcmlhYmlsZSB5IChjb3JyZWxhdGEgYSB4KQoKIyBDYWxjb2xhIGxhIGNvcnJlbGF6aW9uZSBkaSBQZWFyc29uCmNvcnJlbGF0aW9uIDwtIGNvcih4LCB5KQoKIyBTdGFtcGEgaWwgdmFsb3JlIGRpIGNvcnJlbGF6aW9uZQpjYXQoIkNvcnJlbGF6aW9uZSBkaSBQZWFyc29uIHRyYSB4IGUgeToiLCBjb3JyZWxhdGlvbiwgIlxuIikKYGBgCgpJbiBxdWVzdG8gZXNlbXBpbywgc3RpYW1vIGdlbmVyYW5kbyBkYXRpIGNhc3VhbGkgcGVyIGxlIHZhcmlhYmlsaSB4IGUgeS4KTGEgdmFyaWFiaWxlIHkgw6ggY29zdHJ1aXRhIGNvbWUgdW5hIHRyYXNmb3JtYXppb25lIGxpbmVhcmUgZGkgeCBjb24gdW4gdGVybWluZSBkaSBlcnJvcmUgYWdnaXVudG8uClBvaSwgdXRpbGl6emlhbW8gbGEgZnVuemlvbmUgY29yKCkgcGVyIGNhbGNvbGFyZSBsYSBjb3JyZWxhemlvbmUgZGkgUGVhcnNvbiB0cmEgeCBlIHkuCgpVbiB2YWxvcmUgdmljaW5vIGEgMSBpbmRpY2EgdW5hIGNvcnJlbGF6aW9uZSBsaW5lYXJlIHBvc2l0aXZhIGZvcnRlLCB1biB2YWxvcmUgdmljaW5vIGEgLTEgaW5kaWNhIHVuYSBjb3JyZWxhemlvbmUgbGluZWFyZSBuZWdhdGl2YSBmb3J0ZSwgbWVudHJlIHVuIHZhbG9yZSB2aWNpbm8gYSAwIGluZGljYSB1bmEgc2NhcnNhIGNvcnJlbGF6aW9uZSBsaW5lYXJlIHRyYSBsZSBkdWUgdmFyaWFiaWxpLgoKW1Rvcm5hIGFsbCcgW0luZGljZV1dCgojIFJlZ3Jlc3Npb25lIExpbmVhcmUgTXVsdGlwbGEKCkxhICJNdWx0aXBsZSBMaW5lYXIgUmVncmVzc2lvbiIgKFJlZ3Jlc3Npb25lIExpbmVhcmUgTXVsdGlwbGEpIMOoIHVuYSB0ZWNuaWNhIGRpIG1vZGVsbGF6aW9uZSBzdGF0aXN0aWNhIHV0aWxpenphdGEgcGVyIGFuYWxpenphcmUgbGEgcmVsYXppb25lIHRyYSB1bmEgdmFyaWFiaWxlIGRpcGVuZGVudGUgKG8gdGFyZ2V0KSBlIGR1ZSBvIHBpw7kgdmFyaWFiaWxpIGluZGlwZW5kZW50aSAobyBwcmVkaXR0aXZlKS4KUXVlc3RhIHRlY25pY2EgZXN0ZW5kZSBsYSBzZW1wbGljZSByZWdyZXNzaW9uZSBsaW5lYXJlLCBjaGUgY29pbnZvbGdlIHNvbG8gdW5hIHZhcmlhYmlsZSBpbmRpcGVuZGVudGUsIGEgdW4gY29udGVzdG8gaW4gY3VpIHBpw7kgdmFyaWFiaWxpIGluZGlwZW5kZW50aSBzb25vIGNvaW52b2x0ZSBuZWwgbW9kZWxsby4KTGEgcmVncmVzc2lvbmUgbGluZWFyZSBtdWx0aXBsYSDDqCBhbXBpYW1lbnRlIHV0aWxpenphdGEgbmVsbCdhbmFsaXNpIHN0YXRpc3RpY2EgZSBuZWxsJ2FwcHJlbmRpbWVudG8gYXV0b21hdGljbyBwZXIgZmFyZSBwcmV2aXNpb25pIG8gY29tcHJlbmRlcmUgbGUgcmVsYXppb25pIGNvbXBsZXNzZSB0cmEgdmFyaWFiaWxpLgoKJCQgWSA9IFxiZXRhXzAgKyBcYmV0YV8xWF8xICsgLi4uICsgXGJldGFfblhfbiArIFxlcHNpbG9uICQkIEwnb2JpZXR0aXZvIHByaW5jaXBhbGUgw6ggc3RpbWFyZSBpIGNvZWZmaWNpZW50aSDOsiBpbiBtb2RvIGNoZSBpbCBtb2RlbGxvIHNpIGFkYXR0aSBtZWdsaW8gYWkgZGF0aSBvc3NlcnZhdGkuClF1ZXN0byB2aWVuZSBmYXR0byB1dGlsaXp6YW5kbyBtZXRvZGkgZGkgc3RpbWEsIGNvbWUgaWwgbWV0b2RvIGRlaSBtaW5pbWkgcXVhZHJhdGksIGNoZSBjZXJjYSBkaSBtaW5pbWl6emFyZSBsYSBzb21tYSBkZWkgcXVhZHJhdGkgZGVnbGkgZXJyb3JpIHJlc2lkdWkuCklsIG1vZGVsbG8gZGkgcmVncmVzc2lvbmUgdmllbmUgdmFsdXRhdG8gdXRpbGl6emFuZG8gbWV0cmljaGUgZGkgdmFsdXRhemlvbmUgZGVsbGUgcHJlc3RhemlvbmkgY29tZSBsJ2Vycm9yZSBxdWFkcmF0aWNvIG1lZGlvIChSTVNFKSwgaWwgY29lZmZpY2llbnRlIGRpIGRldGVybWluYXppb25lIChSLXNxdWFyZWQpIGUgYWx0cmkuCsOIIGltcG9ydGFudGUgZXNlZ3VpcmUgdGVzdCBkaSBzaWduaWZpY2F0aXZpdMOgIHN0YXRpc3RpY2EgcGVyIGkgY29lZmZpY2llbnRpIGRlbGxlIHZhcmlhYmlsaSBpbmRpcGVuZGVudGkgcGVyIGRldGVybWluYXJlIHNlIGVzc2UgY29udHJpYnVpc2Nvbm8gc2lnbmlmaWNhdGl2YW1lbnRlIGFsIG1vZGVsbG8uCgpMYSByZWdyZXNzaW9uZSBsaW5lYXJlIG11bHRpcGxhIMOoIGJhc2F0YSBzdSBhbGN1bmUgYXNzdW56aW9uaSwgdHJhIGN1aSBsJ2luZGlwZW5kZW56YSBkZWdsaSBlcnJvcmksIGwnb21vc2NoZWRhc3RpY2l0w6AgKHZhcmlhbnphIGNvc3RhbnRlIGRlZ2xpIGVycm9yaSksIGxhIGxpbmVhcml0w6AgZGVsbGEgcmVsYXppb25lIGUgbGEgbm9ybWFsaXTDoCBkZWdsaSBlcnJvcmkuCgpgYGB7cn0KIyBDYXJpY2EgaWwgZGF0YXNldCBtdGNhcnMKZGF0YShtdGNhcnMpCgojIFZpc3VhbGl6emEgbGUgcHJpbWUgcmlnaGUgZGVsIGRhdGFzZXQKaGVhZChtdGNhcnMpCgojIEFkYXR0YW1lbnRvIGRlbCBtb2RlbGxvIGRpIHJlZ3Jlc3Npb25lIGxpbmVhcmUgbXVsdGlwbGEKbW9kZWwgPC0gbG0obXBnIH4gd3QgKyBocCArIHFzZWMsIGRhdGEgPSBtdGNhcnMpCgojIFZpc3VhbGl6emEgdW4gcmllcGlsb2dvIGRlbCBtb2RlbGxvCnN1bW1hcnkobW9kZWwpCmBgYAoKSW4gc2ludGVzaSwgaWwgbW9kZWxsbyBkaSByZWdyZXNzaW9uZSBsaW5lYXJlIG11bHRpcGxhIHN1Z2dlcmlzY2UgY2hlIGlsIHBlc28gZGVsIHZlaWNvbG8gaW5mbHVlbnphIGlsIGNvbnN1bW8gZGkgY2FyYnVyYW50ZS4KTGEgcG90ZW56YSBkZWwgbW90b3JlIGUgaWwgdGVtcG8gZGkgYWNjZWxlcmF6aW9uZSBub24gc29ubyBzaWduaWZpY2F0aXZlIHBlciBsYSBzcGllZ2F6aW9uZSBkaSBxdWVzdG8gbW9kZWxsby4KTm9ub3N0YW50ZSBjacOyIGlsIG1vZGVsbG8gc3BpZWdhIGwnODMlIGRlaSBkZWxsYSB2YXJpYXppb25lIG5laSBjb25zdW1pIGRpIGNhcmJ1cmFudGUuCgpbVG9ybmEgYWxsJyBbSW5kaWNlXV0KCiMjIyBBcHByb2NpbyBNYXRyaWNpYWxlCgpMJ2FwcHJvY2NpbyBtYXRyaWNpYWxlIGFsbGEgcmVncmVzc2lvbmUgw6ggdW5hIGZvcm1hIGFsdGVybmF0aXZhIGRpIHJhcHByZXNlbnRhemlvbmUgZSByaXNvbHV6aW9uZSBkZWkgbW9kZWxsaSBkaSByZWdyZXNzaW9uZSwgaW5jbHVzYSBsYSByZWdyZXNzaW9uZSBsaW5lYXJlLgpRdWVzdG8gYXBwcm9jY2lvIHV0aWxpenphIG5vdGF6aW9uaSBtYXRlbWF0aWNoZSBlIG1hdHJpY2kgcGVyIHNlbXBsaWZpY2FyZSBpIGNhbGNvbGkgZSBvdHRlbmVyZSBzb2x1emlvbmkgcGnDuSBlZmZpY2llbnRpIGluIHByb2JsZW1pIGRpIHJlZ3Jlc3Npb25lIGxpbmVhcmUuCgpDaSBwZXJtZXR0ZSBkaSBwYXNzYXJlIGRhOiAkJCBZID0gXGJldGFfMCArIFxiZXRhXzFYXzEgKyAuLi4gKyBcYmV0YV9uWF9uICsgXGVwc2lsb24gJCQgYSA6ICQkIFkgPSBcYmV0YSBYICsgXGVwc2lsb24gICAkJAoKTGEgc29sdXppb25lIG1hdHJpY2lhbGUgcGVyIHN0aW1hcmUgaSBjb2VmZmljaWVudGkgzrIgw6k6ICQkIFxiZXRhID0gKChYXlQgWCleey0xfSBYXlQgWSkgJCQKCkwnYXBwcm9jY2lvIG1hdHJpY2lhbGUgc2VtcGxpZmljYSBsYSByYXBwcmVzZW50YXppb25lIGUgbGEgcmlzb2x1emlvbmUgZGVpIG1vZGVsbGkgZGkgcmVncmVzc2lvbmUsIHNwZWNpYWxtZW50ZSBxdWFuZG8gc2kgbGF2b3JhIGNvbiBwacO5IHZhcmlhYmlsaSBpbmRpcGVuZGVudGkuCklub2x0cmUsIMOoIHV0aWxlIHBlciBjb21wcmVuZGVyZSBjb21lIGVzZWd1aXJlIGNhbGNvbGkgZGkgcmVncmVzc2lvbmUgaW4gbW9kbyBwacO5IGVmZmljaWVudGUgdXRpbGl6emFuZG8gbWF0cmljaSBlIGFsZ2VicmEgbGluZWFyZSwgc3BlY2lhbG1lbnRlIGluIGNvbnRlc3RpIGRpIGFwcHJlbmRpbWVudG8gYXV0b21hdGljbyBpbiBjdWkgbGUgZGltZW5zaW9uaSBkZWkgZGF0aSBwb3Nzb25vIGVzc2VyZSBlbGV2YXRlLgoKYGBge3J9CiMgQ2FyaWNhIGlsIGRhdGFzZXQgInN3aXNzIiAodW4gZGF0YXNldCBkaSBkYXRpIGRlbW9ncmFmaWNpIHN2aXp6ZXJpKQpkYXRhKHN3aXNzKQoKIyBWaXN1YWxpenphIGxlIHByaW1lIHJpZ2hlIGRlbCBkYXRhc2V0CmhlYWQoc3dpc3MpCgojIENyZWEgbGEgbWF0cmljZSBkZWxsZSB2YXJpYWJpbGkgaW5kaXBlbmRlbnRpClggPC0gYXMubWF0cml4KHN3aXNzWywgYygiRXhhbWluYXRpb24iLCAiRWR1Y2F0aW9uIildKQoKIyBBZ2dpdW5naSB1bmEgY29sb25uYSBkaSAxIHBlciBsJ2ludGVyY2V0dGEKWCA8LSBjYmluZCgxLCBYKQoKIyBDcmVhIGlsIHZldHRvcmUgZGVsbGUgdmFyaWFiaWxpIGRpcGVuZGVudGkKWSA8LSBzd2lzcyRGZXJ0aWxpdHkKCiMgQ2FsY29sYSBpIGNvZWZmaWNpZW50aSBkZWwgbW9kZWxsbyB1dGlsaXp6YW5kbyBsJ2FwcHJvY2NpbyBtYXRyaWNpYWxlCmJldGEgPC0gc29sdmUodChYKSAlKiUgWCkgJSolIHQoWCkgJSolIFkKCiMgVmlzdWFsaXp6YSBpIGNvZWZmaWNpZW50aSBkZWwgbW9kZWxsbwpwcmludChiZXRhKQoKIyBFZmZldHR1YSBwcmV2aXNpb25pIGNvbiBpbCBtb2RlbGxvIG1hdHJpY2lhbGUKcHJlZGljdGlvbnMgPC0gWCAlKiUgYmV0YQoKIyBWYWx1dGEgbGUgcHJlc3RhemlvbmkgZGVsIG1vZGVsbG8KbW9kZWwgPC0gbG0oWSB+IEV4YW1pbmF0aW9uICsgRWR1Y2F0aW9uLCBkYXRhID0gc3dpc3MpICAjIDAgaW5kaWNhIGRpIG5vbiBjYWxjb2xhcmUgbCdpbnRlcmNldHRhCnN1bW1hcnkobW9kZWwpIApgYGAKCi0gICBFc2FtZSAoRXhhbWluYXRpb24pOiBVbiBhdW1lbnRvIG5laSBwdW50ZWdnaSBkaSBlc2FtZSDDqCBhc3NvY2lhdG8gYSB1bmEgZGltaW51emlvbmUgZGVsbGEgZmVydGlsaXTDoCBuZWxsZSByZWdpb25pIHN2aXp6ZXJlLiBRdWVzdG8gc3VnZ2VyaXNjZSBjaGUgdW4gbWlnbGlvcmUgc3RhdG8gZGkgc2FsdXRlIGdlbmVyYWxlLCBtaXN1cmF0byB0cmFtaXRlIGwnZXNhbWUsIMOoIGNvcnJlbGF0byBhIHVuYSBmZXJ0aWxpdMOgIHBpw7kgYmFzc2EuCi0gICBFZHVjYXppb25lIChFZHVjYXRpb24pOiBVbiBhdW1lbnRvIG5lbCBsaXZlbGxvIGRpIGVkdWNhemlvbmUgw6ggY29ycmVsYXRvIGEgdW5hIHJpZHV6aW9uZSBkZWxsYSBmZXJ0aWxpdMOgLiBMZSByZWdpb25pIGNvbiB1biBsaXZlbGxvIGRpIGlzdHJ1emlvbmUgcGnDuSBlbGV2YXRvIHRlbmRvbm8gYWQgYXZlcmUgdW5hIGZlcnRpbGl0w6AgcGnDuSBiYXNzYS4KCltUb3JuYSBhbGwnIFtJbmRpY2VdXQoKIyMjIEludGVycHJldGF6aW9uZSBHZW9tZXRyaWNhCgpMJ2ludGVycHJldGF6aW9uZSBnZW9tZXRyaWNhIGRlbGxhIHJlZ3Jlc3Npb25lIGxpbmVhcmUgw6ggdW4gYXBwcm9jY2lvIGNvbmNldHR1YWxlIGNoZSB1dGlsaXp6YSB1bm8gc3BhemlvIHRyaWRpbWVuc2lvbmFsZSAobyBzdXBlcmlvcmUpIHBlciByYXBwcmVzZW50YXJlIHZpc2l2YW1lbnRlIGlsIG1vZGVsbG8gZGkgcmVncmVzc2lvbmUuCkluIHF1ZXN0byBzcGF6aW8sIG9nbmkgcHVudG8gcmFwcHJlc2VudGEgdW4nb3NzZXJ2YXppb25lIG5lbCBkYXRhc2V0LCBlIHVuIHBpYW5vIChvIGlwZXJwaWFubykgcmFwcHJlc2VudGEgaWwgbW9kZWxsbyBkaSByZWdyZXNzaW9uZS4KTCdvYmlldHRpdm8gw6ggdHJvdmFyZSBpbCBwaWFubyAobyBpcGVycGlhbm8pIGNoZSBtaW5pbWl6emEgbGEgc29tbWEgZGVpIHF1YWRyYXRpIGRlbGxlIGRpc3RhbnplIHZlcnRpY2FsaSB0cmEgaSBwdW50aSBkYXRpIGUgaWwgcGlhbm8gKG8gaXBlcnBpYW5vKS4KUXVlc3RvIGZvcm5pc2NlIHVuYSB2aXN1YWxpenphemlvbmUgaW50dWl0aXZhIGRpIGNvbWUgaSBjb2VmZmljaWVudGkgZGVsIG1vZGVsbG8gdmVuZ29ubyBzdGltYXRpIHBlciBvdHRlbmVyZSBsYSBtaWdsaW9yZSAiYWp1c3RlbWVudCIgYWkgZGF0aSwgbWluaW1penphbmRvIGdsaSBlcnJvcmkgcmVzaWR1aS4KTCdpbnRlcnByZXRhemlvbmUgZ2VvbWV0cmljYSBhaXV0YSBhIGNvbXByZW5kZXJlIGkgcHJpbmNpcGkgZm9uZGFtZW50YWxpIGRlbGxhIHJlZ3Jlc3Npb25lIGxpbmVhcmUgZSBwdcOyIGVzc2VyZSBhcHBsaWNhdGEgYSBwcm9ibGVtaSBwacO5IGNvbXBsZXNzaSBjb24gcGnDuSB2YXJpYWJpbGkgaW5kaXBlbmRlbnRpLgoKYGBgYHtyLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KHBsb3RseSkKCiMgR2VuZXJhIGRhdGkgY2FzdWFsaQpzZXQuc2VlZCgxMjMpCm4gPC0gNTAKWDEgPC0gcm5vcm0obikKWDIgPC0gcm5vcm0obikKWSA8LSAyICogWDEgKyAzICogWDIgKyBybm9ybShuKQoKIyBDcmVhIHVuIGRhdGFmcmFtZSBjb24gbGUgdmFyaWFiaWxpCmRhdGEgPC0gZGF0YS5mcmFtZShYMSwgWDIsIFkpCgojIEFkYXR0YSBpbCBtb2RlbGxvIGRpIHJlZ3Jlc3Npb25lIGxpbmVhcmUKbW9kZWwgPC0gbG0oWSB+IFgxICsgWDIsIGRhdGEgPSBkYXRhKQpzdW1tYXJ5KG1vZGVsKQoKIyBDcmVhemlvbmUgZGkgdW5hIGdyaWdsaWEgZGkgcHVudGkKeDFfcmFuZ2UgPC0gc2VxKG1pbihYMSksIG1heChYMSksIGxlbmd0aCA9IDIwKQp4Ml9yYW5nZSA8LSBzZXEobWluKFgyKSwgbWF4KFgyKSwgbGVuZ3RoID0gMjApCmdyaWQgPC0gZXhwYW5kLmdyaWQoWDEgPSB4MV9yYW5nZSwgWDIgPSB4Ml9yYW5nZSkKCiMgQ2FsY29sbyBkZWxsZSBwcmV2aXNpb25pIGRlbCBtb2RlbGxvIHN1bGxhIGdyaWdsaWEKZ3JpZCRZX3ByZWQgPC0gcHJlZGljdChtb2RlbCwgbmV3ZGF0YSA9IGdyaWQpCgojIENyZWF6aW9uZSBkZWwgcGxvdCAzRCBjb24gcGxvdGx5CiBwbG90X2x5KGRhdGEsIHggPSB+WDEsIHkgPSB+WDIsIHogPSB+WSwgdHlwZSA9ICJzY2F0dGVyM2QiLCBtb2RlID0gIm1hcmtlcnMiLCBtYXJrZXIgPSBsaXN0KHNpemUgPSA1LCBjb2xvciA9ICJibHVlIikpICU+JQogICBhZGRfc3VyZmFjZSgKICAgICB4ID0geDFfcmFuZ2UsCiAgICAgeSA9IHgyX3JhbmdlLAogICAgIHogPSBtYXRyaXgoZ3JpZCRZX3ByZWQsIG5yb3cgPSBsZW5ndGgoeDFfcmFuZ2UpLCBuY29sID0gbGVuZ3RoKHgyX3JhbmdlKSwgYnlyb3cgPSBUUlVFKSwKICAgICBjb2xvcnMgPSAicmVkIiwKICAgICBvcGFjaXR5ID0gMC43CiAgICkgJT4lCiAgIGxheW91dChzY2VuZSA9IGxpc3QoeGF4aXMgPSBsaXN0KHRpdGxlID0gIlgxIiksIHlheGlzID0gbGlzdCh0aXRsZSA9ICJYMiIpLCB6YXhpcyA9IGxpc3QodGl0bGUgPSAiWSIpKSkKCmBgYGAKCkwnaW50ZXJwcmV0YXppb25lIGdlb21ldHJpY2EgY2kgY29uc2VudGUgZGkgdmVkZXJlIGNvbWUgaWwgcGlhbm8gZGkgcmVncmVzc2lvbmUgc2kgYWRhdHRhIGFpIGRhdGkgbmVsbG8gc3BhemlvIHRyaWRpbWVuc2lvbmFsZSBlIGNvbWUgaSBjb2VmZmljaWVudGkgc3RpbWF0aSBpbmZsdWVuemFubyBsYSBwb3NpemlvbmUgZSBsJ2luY2xpbmF6aW9uZSBkZWwgcGlhbm8gcmlzcGV0dG8gYWkgZGF0aSBvc3NlcnZhdGkuClF1ZXN0byBmb3JuaXNjZSB1bmEgdmlzdWFsaXp6YXppb25lIGludHVpdGl2YSBkZWxsYSByZWxhemlvbmUgdHJhIGxlIHZhcmlhYmlsaSBpbmRpcGVuZGVudGkgZSBkaXBlbmRlbnRpIG5lbCBjb250ZXN0byBkZWxsYSByZWdyZXNzaW9uZSBsaW5lYXJlLgoKW1Rvcm5hIGFsbCcgW0luZGljZV1dCgojIyMgRGlzdHJpYnV6aW9uZSBGICYgQW5vdmEgVGFibGUgeyNkaXN0cmlidXppb25lLWYtYW5vdmEtdGFibGV9CgpMJ0FOT1ZBIHZhbHV0YSBnbG9iYWxtZW50ZSBzZSBhbG1lbm8gdW5hIGRlbGxlIHZhcmlhYmlsaSBpbmRpcGVuZGVudGkgaGEgdW4gZWZmZXR0byBzaWduaWZpY2F0aXZvIHN1bGxhIHZhcmlhYmlsZSBkaXBlbmRlbnRlLCBmb3JuaXNjZSB1bmEgc3RhdGlzdGljYSBGIGUgaWwgcmVsYXRpdm8gcC12YWx1ZS4gClVuIHAtdmFsdWUgYmFzc28gc3VnZ2VyaXNjZSBjaGUgYWxtZW5vIHVuYSBkZWxsZSB2YXJpYWJpbGkgaW5kaXBlbmRlbnRpIMOoIHNpZ25pZmljYXRpdmEgbmVsIG1vZGVsbG8uCkwnQU5PVkEgZm9ybmlzY2UgcXVpbmRpIHVuYSB2aXNpb25lIGNvbXBsZXNzaXZhIGRlbGxhIHNpZ25pZmljYXRpdml0w6AgZGVsIG1vZGVsbG8gbmVsIHN1byBjb21wbGVzc28uCgpMJ2FuYWxpc2kgZGVsbGEgdmFyaWFuemEgKEFOT1ZBKSBlIGkgInNpZ25pZi4gY29kZXMiIG5lbCBzdW1tYXJ5IGRlbCBtb2RlbGxvIGZvcm5pc2Nvbm8gaW5mb3JtYXppb25pIHNpbWlsaSwgbWEgc2kgY29uY2VudHJhbm8gc3UgYXNwZXR0aSBkaXZlcnNpIGRlbGwnYW5hbGlzaS4KCkkgInNpZ25pZi4gY29kZXMiIG5lbCBzdW1tYXJ5IGRlbCBtb2RlbGxvIGZvcm5pc2Nvbm8gdW5hIHZhbHV0YXppb25lIHZhcmlhYmlsZSBwZXIgdmFyaWFiaWxlLCBpbmRpY2FuZG8gbGEgc2lnbmlmaWNhdGl2aXTDoCBzdGF0aXN0aWNhIGRpIGNpYXNjdW4gY29lZmZpY2llbnRlLgpVdGlsaXp6YSBhc3RlcmlzY2hpIChcKikgbyBhbHRyaSBzaW1ib2xpIHBlciBpbmRpY2FyZSBpbCBsaXZlbGxvIGRpIHNpZ25pZmljYXRpdml0w6AsIGFkIGVzZW1waW8sICJcKlwqXCoiIHBvdHJlYmJlIGluZGljYXJlIHVuIGxpdmVsbG8gZGkgc2lnbmlmaWNhdGl2aXTDoCBtb2x0byBlbGV2YXRvIChwLXZhbHVlIG1vbHRvIGJhc3NvKSwgbWVudHJlICIgIiAoc3BhemlvKSBwb3RyZWJiZSBpbmRpY2FyZSBub24gc2lnbmlmaWNhdGl2by4KUXVlc3RhIHBhcnRlIGRlbCBzdW1tYXJ5IGZvcm5pc2NlIHVuYSB2aXNpb25lIHBpw7kgZGV0dGFnbGlhdGEgc3VsbGEgc2lnbmlmaWNhdGl2aXTDoCBkaSBjaWFzY3VuYSB2YXJpYWJpbGUgaW5kaXBlbmRlbnRlIHNlcGFyYXRhbWVudGUuCgpMJ0FOT1ZBIHZhbHV0YSBsYSBzaWduaWZpY2F0aXZpdMOgIGRlbCBtb2RlbGxvIG5lbCBzdW8gaW5zaWVtZSwgbWVudHJlIGkgInNpZ25pZi4gY29kZXMiIG5lbCBzdW1tYXJ5IGZvcm5pc2Nvbm8gdW5hIHZpc2lvbmUgZGV0dGFnbGlhdGEgZGVsbGEgc2lnbmlmaWNhdGl2aXTDoCBkaSBjaWFzY3VuYSB2YXJpYWJpbGUgaW5kaXBlbmRlbnRlLgoKKipFc2VtcGlvIDE6KioKCmBgYHtyfQojIENyZWlhbW8gdW4gZGF0YXNldCBmaXR0aXppbwpzZXQuc2VlZCgxMjMpCmRhdGEgPC0gZGF0YS5mcmFtZSgKICBHcnVwcG8gPSByZXAoYygiQSIsICJCIiwgIkMiKSwgZWFjaCA9IDIwKSwKICBQdW50ZWdnaW8gPSBybm9ybSg2MCwgbWVhbiA9IGMoNzAsIDc1LCA4MCksIHNkID0gNSkKKQoKIyBFc2VndWlhbW8gbCdBTk9WQQphbm92YV9yZXN1bHQgPC0gYW92KFB1bnRlZ2dpbyB+IEdydXBwbywgZGF0YSA9IGRhdGEpCgojIFZpc3VhbGl6emlhbW8gbGEgdGFiZWxsYSBBTk9WQQpzdW1tYXJ5KGFub3ZhX3Jlc3VsdCkKYGBgCgpJbiBxdWVzdG8gZXNlbXBpbywgZXNlZ3VpYW1vIHVuJ0FOT1ZBIGEgdW4gZmF0dG9yZSBwZXIgdmFsdXRhcmUgbGUgZGlmZmVyZW56ZSBuZWkgcHVudGVnZ2kgdHJhIGkgZ3J1cHBpIEEsIEIgZSBDLgpJbCByYXBwb3J0byBGIGUgaWwgdmFsb3JlIHAgY2kgcGVybWV0dG9ubyBkaSBkZXRlcm1pbmFyZSBzZSBsZSBkaWZmZXJlbnplIHRyYSBpIGdydXBwaSBzb25vIHN0YXRpc3RpY2FtZW50ZSBzaWduaWZpY2F0aXZlLgoKSSByaXN1bHRhdGkgc3VnZ2VyaXNjb25vIGNoZSBub24gY2kgc29ubyBkaWZmZXJlbnplIHN0YXRpc3RpY2FtZW50ZSBzaWduaWZpY2F0aXZlIHRyYSBpIGdydXBwaSwgb3NzaWEgaWwgdmFyaWFyZSBkZWwgZ3J1cHBvIG5vbiBpbmZsdWVuemEgc2lnbmlmaWNhdGl2YW1lbnRlIGxhIHZhcmlhYmlsZSBkaXBlbmRlbnRlLgpMYSB2YXJpYW56YSB0cmEgaSBncnVwcGkgw6ggbW9sdG8gcGljY29sYSByaXNwZXR0byBhbGxhIHZhcmlhbnphIGFsbCdpbnRlcm5vIGRlaSBncnVwcGksIGUgaWwgdGVzdCBGIG5vbiDDqCBzaWduaWZpY2F0aXZvLgpRdWVzdG8gcHXDsiBpbmRpY2FyZSBjaGUgaSBncnVwcGkgc29ubyBzaW1pbGkgdHJhIGxvcm8gcGVyIHF1YW50byByaWd1YXJkYSBsYSB2YXJpYWJpbGUgaW4gc3R1ZGlvLgoKKipFc2VtcGlvIDI6KioKCmBgYHtyfQojIENyZWlhbW8gdW4gZGF0YXNldCBmaXR0aXppbwpzZXQuc2VlZCgxMjMpCmRhdGEgPC0gZGF0YS5mcmFtZSgKICBHZW5lcmUgPSByZXAoYygiTWFzY2hpbyIsICJGZW1taW5hIiksIGVhY2ggPSA1MCksCiAgVHJhdHRhbWVudG8gPSByZXAoYygiQSIsICJCIiksIHRpbWVzID0gNTApLAogIFB1bnRlZ2dpbyA9IHJub3JtKDEwMCwgbWVhbiA9IGMoNzUsIDgwKSwgc2QgPSA1KQopCgojIEVzZWd1aWFtbyBsJ0FOT1ZBIGEgZHVlIGZhdHRvcmkKYW5vdmFfcmVzdWx0IDwtIGFvdihQdW50ZWdnaW8gfiBHZW5lcmUgKiBUcmF0dGFtZW50bywgZGF0YSA9IGRhdGEpCgojIFZpc3VhbGl6emlhbW8gbGEgdGFiZWxsYSBBTk9WQQpzdW1tYXJ5KGFub3ZhX3Jlc3VsdCkKYGBgCgpJbiBxdWVzdG8gZXNlbXBpbywgZXNlZ3VpYW1vIHVuJ0FOT1ZBIGEgZHVlIGZhdHRvcmkgcGVyIGVzYW1pbmFyZSBsZSBkaWZmZXJlbnplIG5laSBwdW50ZWdnaSBpbiBiYXNlIGFsIGdlbmVyZSBlIGFsIHRyYXR0YW1lbnRvLgoKRGFsbGEgdGFiZWxsYSBkZWxsJ0FOT1ZBIGZvcm5pdGEsIHBvc3NpYW1vIHRyYXJyZSBsZSBzZWd1ZW50aSBjb25jbHVzaW9uaToKCi0gICBJbCBmYXR0b3JlICJUcmF0dGFtZW50byIgaGEgdW4gZm9ydGUgZWZmZXR0byBzdWxsYSB2YXJpYWJpbGUgZGlwZW5kZW50ZSwgY29uIHVuIHZhbG9yZSBkaSBGIGVsZXZhdG8gZSB1biBwLXZhbHVlIG1vbHRvIGJhc3NvLCBpbmRpY2FuZG8gY2hlIGxlIGRpZmZlcmVuemUgdHJhIGkgdHJhdHRhbWVudGkgc29ubyBzdGF0aXN0aWNhbWVudGUgc2lnbmlmaWNhdGl2ZSAoXCpcKlwqKS4KLSAgIElsIGZhdHRvcmUgIkdlbmVyZSIgbm9uIGhhIHVuIGVmZmV0dG8gc2lnbmlmaWNhdGl2byBzdWxsYSB2YXJpYWJpbGUgZGlwZW5kZW50ZSwgY29uIHVuIHZhbG9yZSBkaSBGIGJhc3NvIGUgdW4gcC12YWx1ZSBlbGV2YXRvLgotICAgTCdpbnRlcmF6aW9uZSB0cmEgIkdlbmVyZSIgZSAiVHJhdHRhbWVudG8iIG5vbiBoYSB1biBlZmZldHRvIHNpZ25pZmljYXRpdm8gc3VsbGEgdmFyaWFiaWxlIGRpcGVuZGVudGUsIGNvbiB1biB2YWxvcmUgZGkgRiBlIHVuIHAtdmFsdWUgbm9uIHNpZ25pZmljYXRpdmkuCgpJIHJpc3VsdGF0aSBkZWxsJ0FOT1ZBIHN1Z2dlcmlzY29ubyBjaGUgaWwgIlRyYXR0YW1lbnRvIiDDqCBpbCBwcmluY2lwYWxlIGRyaXZlciBkZWxsZSBkaWZmZXJlbnplIG9zc2VydmF0ZSBuZWxsYSB2YXJpYWJpbGUgZGlwZW5kZW50ZSwgbWVudHJlIGlsICJHZW5lcmUiIGUgbCdpbnRlcmF6aW9uZSB0cmEgIkdlbmVyZSIgZSAiVHJhdHRhbWVudG8iIG5vbiBzZW1icmFubyBhdmVyZSB1biBlZmZldHRvIHNpZ25pZmljYXRpdm8uCgotICAgVW4gdmFsb3JlIEYgbWFnZ2lvcmUgZGkgMSBzdWdnZXJpc2NlIGNoZSBpIHBhcmFtZXRyaSBvIGkgZmF0dG9yaSBzb25vIHNpZ25pZmljYXRpdmksIHBvaWNow6kgbGEgdmFyaWFuemEgc3BpZWdhdGEgw6ggbWFnZ2lvcmUgZGVsbGEgdmFyaWFuemEgbm9uIHNwaWVnYXRhLgotICAgVW4gdmFsb3JlIEYgdmljaW5vIGEgMSBpbmRpY2EgY2hlIGlsIG1vZGVsbG8gbm9uIHNwaWVnYSBpbiBtb2RvIHNpZ25pZmljYXRpdm8gbGEgdmFyaWFiaWxpdMOgIG5laSBkYXRpLgotICAgSWwgdmFsb3JlIHAgYXNzb2NpYXRvIGFsbCdGLXZhbHVlIGZvcm5pc2NlIGxhIHByb2JhYmlsaXTDoCBjaGUgaSByaXN1bHRhdGkgb3NzZXJ2YXRpIHNpYW5vIGRvdnV0aSBhbCBjYXNvLiBVbiB2YWxvcmUgcCBiYXNzbyAoZGkgc29saXRvIGluZmVyaW9yZSBhIDAuMDUpIGluZGljYSB1bmEgc2lnbmlmaWNhdGl2aXTDoCBlbGV2YXRhLCBtZW50cmUgdW4gdmFsb3JlIHAgYWx0byBzdWdnZXJpc2NlIHVuYSBtYW5jYW56YSBkaSBzaWduaWZpY2F0aXZpdMOgLgoKKipTaXN0ZW1hIGRpIGlwb3Rlc2k6KioKCk5lbGwnYW5hbGlzaSBzdGF0aXN0aWNhIGluIGN1aSBzaSBjYWxjb2xhIHVuIHZhbG9yZSBGLCBjaSBzb25vIGR1ZSBpcG90ZXNpIHByaW5jaXBhbGk6IGwnaXBvdGVzaSBudWxsYSAoSDApIGUgbCdpcG90ZXNpIGFsdGVybmF0aXZhIChIMSkuCgpJcG90ZXNpIE51bGxhIChIMCk6IEwnaXBvdGVzaSBudWxsYSBhZmZlcm1hIGNoZSBub24gY2kgc29ubyBkaWZmZXJlbnplIHNpZ25pZmljYXRpdmUgdHJhIGkgZ3J1cHBpIG8gaSBmYXR0b3JpIGNvbnNpZGVyYXRpLgpJbiBhbHRyZSBwYXJvbGUsIGwnaXBvdGVzaSBudWxsYSBzb3N0aWVuZSBjaGUgaSBwYXJhbWV0cmkgZGVsIG1vZGVsbG8gbyBpIGZhdHRvcmkgbm9uIGhhbm5vIHVuIGVmZmV0dG8gc2lnbmlmaWNhdGl2byBzdWwgcmlzdWx0YXRvIG8gY2hlIGxlIGRpZmZlcmVuemUgb3NzZXJ2YXRlIHNvbm8gY2FzdWFsaS4KCklwb3Rlc2kgQWx0ZXJuYXRpdmEgKEgxIG8gSEEpOiBMJ2lwb3Rlc2kgYWx0ZXJuYXRpdmEgw6ggaWwgY29udHJhcmlvIGRlbGwnaXBvdGVzaSBudWxsYS4KU29zdGllbmUgY2hlIGNpIHNvbm8gZGlmZmVyZW56ZSBzaWduaWZpY2F0aXZlIHRyYSBpIGdydXBwaSBvIGkgZmF0dG9yaSBjb25zaWRlcmF0aSwgZSBjaGUgbGUgZGlmZmVyZW56ZSBvc3NlcnZhdGUgbm9uIHNvbm8gY2FzdWFsaSwgbWEgc29ubyBkb3Z1dGUgYSB1biBlZmZldHRvIHNpZ25pZmljYXRpdm8gZGVpIHBhcmFtZXRyaSBkZWwgbW9kZWxsbyBvIGRlaSBmYXR0b3JpLgoKQ29udGludWlhbW8gbCdlc2VtcGlvIGRpIHByaW1hOgoKYGBge3J9Cm1vZGVsIDwtIGxtKFB1bnRlZ2dpbyB+IEdlbmVyZSAqIFRyYXR0YW1lbnRvLCBkYXRhID0gZGF0YSkKc3VtbWFyeShtb2RlbCkKCiMgRXN0cmFpYW1vIGlsIHZhbG9yZSBwCnBfdmFsdWUgPC0gYW5vdmFfc3VtbWFyeVtbMV1dW1siUHIoPkYpIl1dWzNdICAjIFVzaWFtbyBbM10gcGVyIGVzdHJhcnJlIGlsIHZhbG9yZSByZWxhdGl2byBhbGwnaW50ZXJhemlvbmUKCgojIFNjZWdsaWFtbyB1biBsaXZlbGxvIGRpIHNpZ25pZmljYXRpdml0w6AgKGFscGhhKQphbHBoYSA8LSAwLjA1CgojIFZhbHV0aWFtbyBzZSByaWZpdXRhcmUgbCdpcG90ZXNpIG51bGxhCmlmIChwX3ZhbHVlIDwgYWxwaGEpIHsKICBjYXQoIlJpZml1dGlhbW8gbCdpcG90ZXNpIG51bGxhLiBDaSBzb25vIGRpZmZlcmVuemUgc2lnbmlmaWNhdGl2ZSB0cmEgaSBncnVwcGkuXG4iKQp9IGVsc2UgewogIGNhdCgiTm9uIHJpZml1dGlhbW8gbCdpcG90ZXNpIG51bGxhLiBOb24gY2kgc29ubyBkaWZmZXJlbnplIHNpZ25pZmljYXRpdmUgdHJhIGkgZ3J1cHBpLlxuIikKfQpgYGAKCkxhIEYtc3RhdGlzdGljIG5lbCBzdW1tYXJ5IGRpIHVuIG1vZGVsbG8gbGluZWFyZSAobG0pIHJhcHByZXNlbnRhIGxhIHN0YXRpc3RpY2EgZGVsIHRlc3QgRiBwZXIgbCdpbnRlcm8gbW9kZWxsby4gUXVlc3RvIHRlc3QgdmVyaWZpY2Egc2UgYyfDqCBhbG1lbm8gdW5hIHZhcmlhYmlsZSBpbmRpcGVuZGVudGUgbmVsIG1vZGVsbG8gY2hlIMOoIHNpZ25pZmljYXRpdmFtZW50ZSBhc3NvY2lhdGEgYWxsYSB2YXJpYWJpbGUgZGlwZW5kZW50ZS4gSW4gYWx0cmUgcGFyb2xlLCB2YWx1dGEgbCdpcG90ZXNpIG51bGxhIGNoZSB0dXR0aSBpIGNvZWZmaWNpZW50aSBkZWxsZSB2YXJpYWJpbGkgaW5kaXBlbmRlbnRpIG5lbCBtb2RlbGxvIHNpYW5vIHVndWFsaSBhIHplcm8gKGNpb8OoIGNoZSBub24gY2kgc2lhbm8gZWZmZXR0aSkuCgpJbiBicmV2ZSBsYSBGLXN0YXRpc3RpYyBzdWdnZXJpc2NlIGNoZSBhbG1lbm8gdW5hIGRlbGxlIGludGVyYXppb25pIHRyYSAiR2VuZXJlIiBlICJUcmF0dGFtZW50byIgbyBhbG1lbm8gdW5hIGRlbGxlIHByaW5jaXBhbGkgZWZmZXR0aSDDqCBzaWduaWZpY2F0aXZhIG5lbCBtb2RlbGxvLgoKW1Rvcm5hIGFsbCcgW0luZGljZV1dCgojIyMgTW9kZWxsaSBOaWRpZmljYXRpCgpOZWkgbW9kZWxsaSBzdGF0aXN0aWNpLCB1biAibmVzdGVkIG1vZGVsIiBzaSB2ZXJpZmljYSBxdWFuZG8gdW4gbW9kZWxsbyBwacO5IGNvbXBsZXNzbyBvIGdlbmVyYWxlIHB1w7IgZXNzZXJlIHN1ZGRpdmlzbyBvIHNlbXBsaWZpY2F0byBpbiB1biBtb2RlbGxvIHBpw7kgc2VtcGxpY2UgbyBzcGVjaWZpY28uCklsIG1vZGVsbG8gcGnDuSBzZW1wbGljZSDDqCBjb25zaWRlcmF0byAibmlkaWZpY2F0byIgYWxsJ2ludGVybm8gZGVsIG1vZGVsbG8gcGnDuSBjb21wbGVzc28sIHBvaWNow6kgY29udGllbmUgdW4gc290dG9pbnNpZW1lIGRpIHBhcmFtZXRyaSBvIHZpbmNvbGkgZGVsIG1vZGVsbG8gcGnDuSBnZW5lcmFsZS4KCk5lbCBjb250ZXN0byBkZWxsYSByZWdyZXNzaW9uZSwgaSBtb2RlbGxpIG5pZGlmaWNhdGkgc29ubyBzcGVzc28gdXRpbGl6emF0aSBwZXIgdGVzdGFyZSBsJ2FnZ2l1bnRhIGRpIHZhcmlhYmlsaSBpbmRpcGVuZGVudGkgYWwgbW9kZWxsbyBhbCBmaW5lIGRpIHZhbHV0YXJlIHNlIGxlIHZhcmlhYmlsaSBhZ2dpdW50aXZlIG1pZ2xpb3Jhbm8gc2lnbmlmaWNhdGl2YW1lbnRlIGxhIGNhcGFjaXTDoCBkaSBwcmV2aXNpb25lIG8gc3BpZWdhemlvbmUgZGVsIG1vZGVsbG8uCkkgbW9kZWxsaSBuaWRpZmljYXRpIHNvbm8gYW5jaGUgdXRpbGl6emF0aSBpbiBjb250ZXN0aSBjb21lIGwnYW5hbGlzaSBkZWxsYSB2YXJpYW56YSAoQU5PVkEpLCBsJ2FuYWxpc2kgZGVsbGEgZGV2aWFuemEgbmVpIG1vZGVsbGkgbGluZWFyaSBnZW5lcmFsaXp6YXRpIChjaGUgdmVkcmVtbyBwacO5IGF2YW50aSkgZSBhbHRyZSBwcm9jZWR1cmUgc3RhdGlzdGljaGUuCgpFc2VtcGlvIGRpIE1vZGVsbGkgZGkgUmVncmVzc2lvbmUgTmlkaWZpY2F0aToKClN1cHBvbmlhbW8gZGkgdm9sZXIgY3JlYXJlIHVuIG1vZGVsbG8gZGkgcmVncmVzc2lvbmUgcGVyIHByZXZlZGVyZSBpbCByZWRkaXRvIGRpIHVuYSBwZXJzb25hIGJhc2FuZG9jaSBzdSBxdWF0dHJvIHZhcmlhYmlsaSBpbmRpcGVuZGVudGk6IGV0w6AsIGlzdHJ1emlvbmUsIGVzcGVyaWVuemEgbGF2b3JhdGl2YSBlIGdlbmVyZS4KSWwgbW9kZWxsbyBjb21wbGV0byBwb3RyZWJiZSBlc3NlcmU6CgoqKk1vZGVsbG8gQ29tcGxldG8qKgoKJCQgUmVkZGl0byA9IFxiZXRhXzAgKyBcYmV0YV8xIFxjZG90IEV0w6AgKyBcYmV0YV8yIFxjZG90IElzdHJ1emlvbmUgKyBcYmV0YV8zIFxjZG90IEVzcGVyaWVuemEgKyBcYmV0YV80IFxjZG90IEdlbmVyZSAkJCBUdXR0YXZpYSwgcG90cmVtbW8gZXNzZXJlIGludGVyZXNzYXRpIGEgdmFsdXRhcmUgc2UgbCdhZ2dpdW50YSBkZWxsYSB2YXJpYWJpbGUgImdlbmVyZSIgbWlnbGlvcmEgc2lnbmlmaWNhdGl2YW1lbnRlIGxhIGNhcGFjaXTDoCBwcmVkaXR0aXZhIGRlbCBtb2RlbGxvLgpJbiB0YWwgY2FzbywgaWwgbW9kZWxsbyBzZW56YSAiZ2VuZXJlIiDDqCBuaWRpZmljYXRvIGFsbCdpbnRlcm5vIGRlbCBtb2RlbGxvIGNvbXBsZXRvOgoKKipNb2RlbGxvIE5pZGlmaWNhdG8qKgoKJCQgUmVkZGl0bycgPSBcYmV0YV8wICsgXGJldGFfMSBcY2RvdCBFdMOgICsgXGJldGFfMiBcY2RvdCBJc3RydXppb25lICsgXGJldGFfMyBcY2RvdCBFc3BlcmllbnphICQkCgpJbiBxdWVzdG8gZXNlbXBpbywgaWwgTW9kZWxsbyAxIMOoIGlsIG1vZGVsbG8gY29tcGxldG8gZSBpbCBNb2RlbGxvIDIgw6ggaWwgbW9kZWxsbyBuaWRpZmljYXRvIHNlbnphIGlsIHBhcmFtZXRybyBwZXIgImdlbmVyZSIuClZhbHV0aWFtbyB0cmFtaXRlIHVuIEFOT1ZBIHF1YWxlIGRlaSBkdWUgbW9kZWxsaSBzaWEgY29uc2lkZXJhdG8gcGnDuSBzaWduaWZpY2F0aXZvLgoKCmBgYHtyfQojIENyZWlhbW8gZGF0aSBmaXR0aXppCnNldC5zZWVkKDEyMykKbiA8LSAxMDAKZXRhIDwtIHJub3JtKG4sIG1lYW4gPSAzNSwgc2QgPSA1KQppc3RydXppb25lIDwtIHJub3JtKG4sIG1lYW4gPSAxMiwgc2QgPSAyKQplc3BlcmllbnphIDwtIHJub3JtKG4sIG1lYW4gPSAxMCwgc2QgPSAzKQpnZW5lcmUgPC0gc2FtcGxlKGMoIk1hc2NoaW8iLCAiRmVtbWluYSIpLCBuLCByZXBsYWNlID0gVFJVRSkKcmVkZGl0byA8LSAyMCArIDIgKiBldGEgKyAzICogaXN0cnV6aW9uZSArIDUgKiBlc3BlcmllbnphICsgaWZlbHNlKGdlbmVyZSA9PSAiTWFzY2hpbyIsIDQsIDApICsgcm5vcm0obiwgbWVhbiA9IDAsIHNkID0gNSkKCiMgQ3JlaWFtbyB1biBkYXRhZnJhbWUgY29uIGkgZGF0aQpkYXRhIDwtIGRhdGEuZnJhbWUoZXRhLCBpc3RydXppb25lLCBlc3BlcmllbnphLCBnZW5lcmUsIHJlZGRpdG8pCgojIE1vZGVsbG8gY29tcGxldG8KbW9kZWxsb19jb21wbGV0byA8LSBsbShyZWRkaXRvIH4gZXRhICsgaXN0cnV6aW9uZSArIGVzcGVyaWVuemEgKyBnZW5lcmUsIGRhdGEgPSBkYXRhKQoKIyBNb2RlbGxvIG5pZGlmaWNhdG8gc2VuemEgImdlbmVyZSIKbW9kZWxsb19uaWRpZmljYXRvIDwtIGxtKHJlZGRpdG8gfiBldGEgKyBpc3RydXppb25lICsgZXNwZXJpZW56YSwgZGF0YSA9IGRhdGEpCgojIFRlc3QgRiBwZXIgY29uZnJvbnRhcmUgaSBtb2RlbGxpCmFub3ZhX3Jlc3VsdCA8LSBhbm92YShtb2RlbGxvX25pZGlmaWNhdG8sIG1vZGVsbG9fY29tcGxldG8pCgojIFZpc3VhbGl6emlhbW8gbGEgdGFiZWxsYSBBTk9WQQpwcmludChhbm92YV9yZXN1bHQpCgojIFNjZWdsaWFtbyB1biBsaXZlbGxvIGRpIHNpZ25pZmljYXRpdml0w6AgKGFscGhhKQphbHBoYSA8LSAwLjA1CgojIFZhbHV0aWFtbyBzZSByaWZpdXRhcmUgbCdpcG90ZXNpIG51bGxhCmlmIChhbm92YV9yZXN1bHRbMiwgIlByKD5GKSJdIDwgYWxwaGEpIHsKICBjYXQoIkxhIHJpbW96aW9uZSBkaSAnZ2VuZXJlJyBub24gbWlnbGlvcmEgc2lnbmlmaWNhdGl2YW1lbnRlIGlsIG1vZGVsbG8uXG4iKQp9IGVsc2UgewogIGNhdCgiTGEgcmltb3ppb25lIGRpICdnZW5lcmUnIG1pZ2xpb3JhIHNpZ25pZmljYXRpdmFtZW50ZSBpbCBtb2RlbGxvLlxuIikKfQoKIyBSIFNxdWFyZWQgZGVpIGR1ZSBtb2RlbGxpCnByaW50KCJNb2RlbGxvIGNvbXBsZXRvICIpIApzdW1tYXJ5KG1vZGVsbG9fY29tcGxldG8pJHIuc3F1YXJlZApwcmludCgiTW9kZWxsbyBhbm5pZGF0byAiKQpzdW1tYXJ5KG1vZGVsbG9fbmlkaWZpY2F0bykkci5zcXVhcmVkCmBgYAoKW1Rvcm5hIGFsbCcgW0luZGljZV1dCgojIyMgU2VsZXppb25lIGRlbGxlIHZhcmlhYmlsaQoKTGEgInZhcmlhYmxlIHNlbGVjdGlvbiIgw6ggdW4gcHJvY2Vzc28gYXR0cmF2ZXJzbyBpbCBxdWFsZSBzaSBzY2VsZ29ubyBsZSB2YXJpYWJpbGkgcGnDuSByaWxldmFudGkgZGEgaW5jbHVkZXJlIGluIHVuIG1vZGVsbG8gc3RhdGlzdGljby4KUXVlc3RvIHByb2Nlc3NvIMOoIHV0aWxlIHBlciBzZW1wbGlmaWNhcmUgaSBtb2RlbGxpLCBtaWdsaW9yYXJlIGxhIGNhcGFjaXTDoCBwcmVkaXR0aXZhIGUgbGEgY29tcHJlbnNpb25lIGRlaSBkYXRpLCByaWR1cnJlIGwnb3ZlcmZpdHRpbmcgZSBhdW1lbnRhcmUgbCdlZmZpY2llbnphIGNvbXB1dGF6aW9uYWxlLgoKVW4gbWV0b2RvIGNvbXVuZSBwZXIgbGEgc2VsZXppb25lIGRlbGxlIHZhcmlhYmlsaSBpbiBSIGNvaW52b2xnZSBsJ3V0aWxpenpvIGRlbGwnSW5mb3JtYXRpb24gQ3JpdGVyaW9uIChDcml0ZXJpbyBkJ0luZm9ybWF6aW9uZSkgZGkgQWthaWtlIChBSUMpIGluc2llbWUgYWxsYSBmdW56aW9uZSBzdGVwKCkuCgoqKkFJQyAoQWthaWtlJ3MgSW5mb3JtYXRpb24gQ3JpdGVyaW9uKToqKgoKSWwgQ3JpdGVyaW8gZCdJbmZvcm1hemlvbmUgZGkgQWthaWtlIChBSUMpIMOoIHVuYSBtZXRyaWNhIGNoZSBtaXN1cmEgbGEgcXVhbGl0w6AgZGkgdW4gbW9kZWxsbyBzdGF0aXN0aWNvLgpMJ29iaWV0dGl2byBkZWxsJ0FJQyDDqCB0cm92YXJlIGlsIG1pZ2xpb3IgY29tcHJvbWVzc28gdHJhIGxhIGJvbnTDoCBkaSBhZGF0dGFtZW50byBkZWwgbW9kZWxsbyBhaSBkYXRpIGUgbGEgc3VhIGNvbXBsZXNzaXTDoC4KTCdBSUMgdGllbmUgY29udG8gZGVsbGEgZnVuemlvbmUgZGkgdmVyb3NpbWlnbGlhbnphIGRlbCBtb2RlbGxvIGUgcGVuYWxpenphIGkgbW9kZWxsaSBjb24gdW4gbnVtZXJvIG1hZ2dpb3JlIGRpIHBhcmFtZXRyaS4KTCdBSUMgw6ggZGVmaW5pdG8gY29tZToKCiQkIEFJQyA9IC0ybG9nTGlrZWxpaG9vZCArIDJrICQkCgpEb3ZlOgoKLSAgICJsb2ctbGlrZWxpaG9vZCIgw6ggaWwgbG9nYXJpdG1vIGRlbGxhIGZ1bnppb25lIGRpIHZlcm9zaW1pZ2xpYW56YSBkZWwgbW9kZWxsby4KLSAgICJrIiDDqCBpbCBudW1lcm8gZGkgcGFyYW1ldHJpIHN0aW1hdGkgbmVsIG1vZGVsbG8uIFVuIHZhbG9yZSBBSUMgcGnDuSBiYXNzbyBpbmRpY2EgdW4gbW9kZWxsbyBtaWdsaW9yZSwgaW4gcXVhbnRvIGluZGljYSB1biBtaWdsaW9yZSBhZGF0dGFtZW50byBhaSBkYXRpIGNvbiBtZW5vIGNvbXBsZXNzaXTDoC4KCioqRnVuemlvbmUgc3RlcCgpOioqCgpMYSBmdW56aW9uZSBzdGVwKCkgaW4gUiDDqCB1dGlsaXp6YXRhIHBlciBlZmZldHR1YXJlIGxhIHNlbGV6aW9uZSBkZWxsZSB2YXJpYWJpbGkgYmFzYXRhIHN1IGNyaXRlcmkgY29tZSBsJ0FJQy4KQ29uc2VudGUgZGkgY29uZnJvbnRhcmUgZSBzZWxlemlvbmFyZSBpIG1vZGVsbGkgaW4gbW9kbyBhdXRvbWF0aWNvIGFnZ2l1bmdlbmRvIG8gcmltdW92ZW5kbyB2YXJpYWJpbGkgZGFsIG1vZGVsbG8sIGZpbm8gYSB0cm92YXJlIGlsIG1vZGVsbG8gY29uIGwnQUlDIHBpw7kgYmFzc28uCkxhIHNpbnRhc3NpIGRpIGJhc2UgZGVsbGEgZnVuemlvbmUgc3RlcCgpIMOoIGxhIHNlZ3VlbnRlOgoKYGBge3J9CiNzdGVwKG1vZGVsbG9faW5pemlhbGUsIGRpcmVjdGlvbiA9ICJib3RoIiwgc2NvcGUgPSBsaXN0KGxvd2VyID0gbW9kZWxsb19taW5pbW8sIHVwcGVyID0gbW9kZWxsb19tYXNzaW1vKSkKYGBgCgotICAgbW9kZWxsb19pbml6aWFsZSDDqCBpbCBtb2RlbGxvIGRpIHBhcnRlbnphIGNoZSBkZXNpZGVyaSBzZW1wbGlmaWNhcmUgbyBtaWdsaW9yYXJlLgotICAgZGlyZWN0aW9uIHB1w7IgZXNzZXJlICJmb3J3YXJkIiwgImJhY2t3YXJkIiwgbyAiYm90aCIgZSBzcGVjaWZpY2Egc2UgYWdnaXVuZ2VyZSwgcmltdW92ZXJlIG8gZW50cmFtYmkgaSB0aXBpIGRpIHZhcmlhYmlsaSBkdXJhbnRlIGxhIHNlbGV6aW9uZS4KLSAgIHNjb3BlIHNwZWNpZmljYSBsJ2ludGVydmFsbG8gZGVpIG1vZGVsbGkgZGEgY29uc2lkZXJhcmUgZHVyYW50ZSBsYSBzZWxlemlvbmUuIElsIC0gIm1vZGVsbG9fbWluaW1vIiByYXBwcmVzZW50YSBpbCBtb2RlbGxvIHBpw7kgc2VtcGxpY2UgcG9zc2liaWxlIChhZCBlc2VtcGlvLCB1biBtb2RlbGxvIGNvbiBzb2xvIGwnaW50ZXJjZXR0YSksIG1lbnRyZSBpbCAibW9kZWxsb19tYXNzaW1vIiByYXBwcmVzZW50YSBpbCBtb2RlbGxvIHBpw7kgY29tcGxlc3NvIChpbCBtb2RlbGxvIGNvbXBsZXRvIGNvbiB0dXR0ZSBsZSB2YXJpYWJpbGkpLgoKYGBge3J9CiMgQ2FyaWNhIGlsIGRhdGFzZXQgZGkgZXNlbXBpbwpkYXRhKG10Y2FycykKCiMgQ3JlYSB1biBtb2RlbGxvIGxpbmVhcmUgaW5pemlhbGUKYWxsIDwtIGxtKG1wZyB+IC4sIGRhdGEgPSBtdGNhcnMpCgojIEVzZWd1aSBsYSBzZWxlemlvbmUgZGVsbGUgdmFyaWFiaWxpIGJhc2F0YSBzdSBBSUMKYmVzdCA8LSBzdGVwKGFsbCwgZGlyZWN0aW9uID0gImJhY2t3YXJkIikKYGBgCgpJbiBxdWVzdG8gZXNlbXBpbywgcGFydGlhbW8gZGEgdW4gbW9kZWxsbyBsaW5lYXJlIGNvbXBsZXRvIGNoZSB1dGlsaXp6YSB0dXR0ZSBsZSB2YXJpYWJpbGkgZGkgbXRjYXJzLCBlIHBvaSB1dGlsaXp6aWFtbyBzdGVwKCkgcGVyIGVzZWd1aXJlIGxhIHNlbGV6aW9uZSBkZWxsZSB2YXJpYWJpbGkgYmFzYXRhIHN1IEFJQy4KQWxsYSBmaW5lLCBvdHRlbmlhbW8gaWwgbW9kZWxsbyBjb24gbCdBSUMgcGnDuSBiYXNzbywgY2hlIGRvdnJlYmJlIGVzc2VyZSB1bmEgdmVyc2lvbmUgc2VtcGxpZmljYXRhIGRlbCBtb2RlbGxvIGluaXppYWxlIGNvbiBzb2xvIGxlIHZhcmlhYmlsaSBwacO5IHJpbGV2YW50aS4KCkxhICJ2YXJpYWJsZSBzZWxlY3Rpb24iIHV0aWxpenphbmRvIEFJQyBlIHN0ZXAoKSDDqCB1biBwb3RlbnRlIHN0cnVtZW50byBwZXIgbWlnbGlvcmFyZSBsYSBxdWFsaXTDoCBlIGwnaW50ZXJwcmV0YWJpbGl0w6AgZGVpIG1vZGVsbGkgc3RhdGlzdGljaSwgaW4gcGFydGljb2xhcmUgcXVhbmRvIHNpIGhhbm5vIG1vbHRpIHBvdGVuemlhbGkgcHJlZGl0dG9yaS4KCltUb3JuYSBhbGwnIFtJbmRpY2VdXQoKIyMjIFByZWRpemlvbmkgQ2F0ZWdvcmljaGUKCk5lbGwnYW5hbGlzaSBzdGF0aXN0aWNhLCBpICJjYXRlZ29yaWNhbCBwcmVkaWN0b3JzIiBzb25vIHZhcmlhYmlsaSBjaGUgcmFwcHJlc2VudGFubyBjYXRlZ29yaWUgbyBncnVwcGkgZGlzdGludGkgYW56aWNow6kgdmFsb3JpIG51bWVyaWNpLgpRdWVzdGUgdmFyaWFiaWxpIHNvbm8gYW5jaGUgY29ub3NjaXV0ZSBjb21lIHZhcmlhYmlsaSBxdWFsaXRhdGl2ZSBvIGZhdHRvcmkuCkFkIGVzZW1waW8sIGlsIGdlbmVyZSAobWFzY2hpby9mZW1taW5hKSwgaWwgbGl2ZWxsbyBkaSBpc3RydXppb25lIChzY3VvbGEgZWxlbWVudGFyZSwgc2N1b2xhIG1lZGlhLCBsYXVyZWEpLCBvIGlsIHRpcG8gZGkgcHJvZG90dG8gKEEsIEIsIEMpIHNvbm8gZXNlbXBpIGRpIHByZWRpdHRvcmkgY2F0ZWdvcmljaS4KUXVhbmRvIHNpIHV0aWxpenphbm8gcHJlZGl0dG9yaSBjYXRlZ29yaWNpIGluIHVuIG1vZGVsbG8gc3RhdGlzdGljbywgw6ggaW1wb3J0YW50ZSBjb25zaWRlcmFyZSBjb21lIGdlc3RpcmUgZSBpbnRlcnByZXRhcmUgcXVlc3RpIGRhdGkuCgpVbmEgY29uc2lkZXJhemlvbmUgZm9uZGFtZW50YWxlIMOoIGNvbWUgcmFwcHJlc2VudGFyZSBsZSB2YXJpYWJpbGkgY2F0ZWdvcmljaGUgbmVsIG1vZGVsbG8uClNvbGl0YW1lbnRlLCB2ZW5nb25vIHV0aWxpenphdGUgZGVsbGUgdmFyaWFiaWxpIGR1bW15ICh2YXJpYWJpbGkgaW5kaWNhdHJpY2kpIHBlciByYXBwcmVzZW50YXJlIGxlIGNhdGVnb3JpZS4KQWQgZXNlbXBpbywgbmVsIGNhc28gZGVsIGdlbmVyZSAobWFzY2hpby9mZW1taW5hKSwgcG90cmViYmVybyBlc3NlcmUgY3JlYXRlIGR1ZSB2YXJpYWJpbGkgZHVtbXksIHVuYSBwZXIgaWwgbWFzY2hpbyBlIHVuYSBwZXIgbGEgZmVtbWluYS4KUXVlc3RlIHZhcmlhYmlsaSBkdW1teSBwcmVuZG9ubyBpbCB2YWxvcmUgMSBvIDAgYSBzZWNvbmRhIGRlbGwnYXBwYXJ0ZW5lbnphIGFsbGEgY2F0ZWdvcmlhLgpRdWVzdG8gYXBwcm9jY2lvIGNvbnNlbnRlIGFsIG1vZGVsbG8gZGkgY2F0dHVyYXJlIGwnZWZmZXR0byBkZWxsYSBjYXRlZ29yaWEgc3VsbGEgdmFyaWFiaWxlIGRpcGVuZGVudGUuCgpPbHRyZSBhbGxhIHJhcHByZXNlbnRhemlvbmUgZGVsbGUgdmFyaWFiaWxpIGNhdGVnb3JpY2hlLCDDqCBpbXBvcnRhbnRlIGNvbnNpZGVyYXJlIGxlIGludGVyYXppb25pIHRyYSBpIHByZWRpdHRvcmkuCkxlIGludGVyYXppb25pIHNpIHZlcmlmaWNhbm8gcXVhbmRvIGwnZWZmZXR0byBkaSB1bmEgdmFyaWFiaWxlIGNhdGVnb3JpY2Egc3VsIHJpc3VsdGF0byBkaXBlbmRlIGRhIHVuJ2FsdHJhIHZhcmlhYmlsZS4KQWQgZXNlbXBpbywgbCdlZmZldHRvIGRlbCBsaXZlbGxvIGRpIGlzdHJ1emlvbmUgc3VsIHJlZGRpdG8gcG90cmViYmUgdmFyaWFyZSBpbiBiYXNlIGFsIGdlbmVyZS4KSW4gcXVlc3RvIGNhc28sIGMnw6ggdW4naW50ZXJhemlvbmUgdHJhIGlsIGxpdmVsbG8gZGkgaXN0cnV6aW9uZSBlIGlsIGdlbmVyZS4KClBlciBlc2FtaW5hcmUgbGUgaW50ZXJhemlvbmkgdHJhIHByZWRpdHRvcmkgY2F0ZWdvcmljaSwgw6ggcG9zc2liaWxlIHV0aWxpenphcmUgbCdhbmFsaXNpIGRlbGxhIHZhcmlhbnphIChBTk9WQSkgbyBpIG1vZGVsbGkgbGluZWFyaSBnZW5lcmFsaXp6YXRpIChjaGUgdmVkcmVtbyBwacO5IGF2YW50aSkuCkxlIGludGVyYXppb25pIHBvc3Nvbm8gZm9ybmlyZSBpbmZvcm1hemlvbmkgcHJlemlvc2Ugc3VsbCdpbmZsdWVuemEgY29tYmluYXRhIGRlbGxlIHZhcmlhYmlsaSBjYXRlZ29yaWNoZSBzdWwgcmlzdWx0YXRvLgoKYGBge3J9CiMgQ3JlaWFtbyBkYXRpIGZpdHRpemkKc2V0LnNlZWQoMTIzKQpuIDwtIDEwMApnZW5lcmUgPC0gc2FtcGxlKGMoIk1hc2NoaW8iLCAiRmVtbWluYSIpLCBuLCByZXBsYWNlID0gVFJVRSkKaXN0cnV6aW9uZSA8LSByZXAoYygiRWxlbWVudGFyZSIsICJNZWRpYSIsICJMYXVyZWEiKSwgbGVuZ3RoLm91dCA9IG4gKQpyZWRkaXRvIDwtIDMwICsgaWZlbHNlKGdlbmVyZSA9PSAiTWFzY2hpbyIsIDUsIDApICsgaWZlbHNlKGlzdHJ1emlvbmUgPT0gIkxhdXJlYSIsIDEwLCAwKSArIHJub3JtKG4sIG1lYW4gPSAwLCBzZCA9IDUpCgojIENyZWlhbW8gdW4gZGF0YWZyYW1lIGNvbiBpIGRhdGkKZGF0YSA8LSBkYXRhLmZyYW1lKGdlbmVyZSwgaXN0cnV6aW9uZSwgcmVkZGl0bykKCiMgTW9kZWxsbyBjb24gaW50ZXJhemlvbmUgdHJhIGdlbmVyZSBlIGlzdHJ1emlvbmUKbW9kZWxsbyA8LSBsbShyZWRkaXRvIH4gZ2VuZXJlICogaXN0cnV6aW9uZSwgZGF0YSA9IGRhdGEpCgojIFZpc3VhbGl6emlhbW8gaSByaXN1bHRhdGkKc3VtbWFyeShtb2RlbGxvKQphbm92YShtb2RlbGxvLCB0ZXN0ID0gImNoaSIpCgojIEdyYWZpY28gcmVkZGl0byBwZXIgc29saSBtYXNjaGkgZSBzb2xlIGZlbW1pbmUKZ2dwbG90KGRhdGEgPSBkYXRhLCBhZXMoeCA9IGlzdHJ1emlvbmUsIHkgPSByZWRkaXRvLCBmaWxsID0gZ2VuZXJlKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBsYWJzKHggPSAiSXN0cnV6aW9uZSIsIHkgPSAiUmVkZGl0byIpCmBgYAoKSW4gcXVlc3RvIGVzZW1waW8sIHN0aWFtbyBjcmVhbmRvIGRhdGkgZml0dGl6aSBjb24gZHVlIHByZWRpdHRvcmkgY2F0ZWdvcmljaTogImdlbmVyZSIgZSAiaXN0cnV6aW9uZSIuCklsIG1vZGVsbG8gbGluZWFyZSBpbmNsdWRlIHVuJ2ludGVyYXppb25lIHRyYSBxdWVzdGkgZHVlIHByZWRpdHRvcmkuCkxhIHRhYmVsbGEgZGVpIHJpc3VsdGF0aSBzdW1tYXJ5KG1vZGVsbG8pIG1vc3RyYSBjb21lIGkgcHJlZGl0dG9yaSBjYXRlZ29yaWNpIGUgbCdpbnRlcmF6aW9uZSBpbmZsdWVuemFubyBpbCByZWRkaXRvLgoKUG9zc2lhbW8gY29uY2x1ZGVyZSBjaGUgaWwgZ2VuZXJlIGUgaWwgbGl2ZWxsbyBkaSBpc3RydXppb25lIGhhbm5vIHVuIGVmZmV0dG8gc2lnbmlmaWNhdGl2byBzdWwgcmVkZGl0bywgbWVudHJlIGxlIGludGVyYXppb25pIHRyYSBnZW5lcmUgZSBpc3RydXppb25lIG5vbiBzb25vIHNpZ25pZmljYXRpdmUgaW4gcXVlc3RvIG1vZGVsbG8uCklsIG1vZGVsbG8gbmVsIHN1byBjb21wbGVzc28gw6ggc2lnbmlmaWNhdGl2byBlIGluIGdyYWRvIGRpIHNwaWVnYXJlIHVuYSBwYXJ0ZSBkZWxsYSB2YXJpYXppb25lIG5lbCByZWRkaXRvLgoKKipGYXR0b3JpIGNvbiBwacO5IGRpIGR1ZSBjYXRlZ29yaWU6KioKClF1YW5kbyBzaSBhZmZyb250YW5vIGZhdHRvcmkgY29uIHBpw7kgZGkgZHVlIGxpdmVsbGkgKGNhdGVnb3JpZSksIMOoIG5lY2Vzc2FyaW8gY29uc2lkZXJhcmUgY29tZSBnZXN0aXJlIHF1ZXN0ZSB2YXJpYWJpbGkgbmVsIG1vZGVsbG8uCkluIGdlbmVyYWxlLCB1biBmYXR0b3JlIGNvbiBrIGxpdmVsbGkgcmljaGllZGUgbGEgY3JlYXppb25lIGRpIGstMSB2YXJpYWJpbGkgZHVtbXkgcGVyIGV2aXRhcmUgbGEgImR1bW15IHZhcmlhYmxlIHRyYXAiLgpRdWVzdG8gc2kgdmVyaWZpY2EgcXVhbmRvIGxlIHZhcmlhYmlsaSBkdW1teSBzb25vIGxpbmVhcm1lbnRlIGRpcGVuZGVudGkgZSBwb3Nzb25vIHBvcnRhcmUgYSBwcm9ibGVtaSBkaSBtdWx0aWNvbGxpbmVhcml0w6AuCgpBZCBlc2VtcGlvLCBzZSBhYmJpYW1vIHVuYSB2YXJpYWJpbGUgImNvbG9yZSIgY29uIHRyZSBsaXZlbGxpIChyb3NzbywgdmVyZGUsIGJsdSksIGRvdnJlbW1vIGNyZWFyZSBkdWUgdmFyaWFiaWxpIGR1bW15IHBlciByYXBwcmVzZW50YXJsYS4KVW5hIHJhcHByZXNlbnRlcsOgIGlsIHJvc3NvIGUgbCdhbHRyYSBpbCB2ZXJkZS4KU2UgZW50cmFtYmUgbGUgdmFyaWFiaWxpIGR1bW15IHNvbm8gdWd1YWxpIGEgMCwgY2nDsiBzaWduaWZpY2EgY2hlIGlsIGNvbG9yZSDDqCBibHUuClF1ZXN0byBldml0YSBsYSB0cmFwIGRlbGxhIHZhcmlhYmlsZSBkdW1teS4KCmBgYHtyfQojIENyZWlhbW8gZGF0aSBmaXR0aXppCnNldC5zZWVkKDEyMykKbiA8LSAxMDAKY29sb3JlIDwtIHJlcChjKCJSb3NzbyIsICJWZXJkZSIsICJCbHUiKSwgbGVuZ3RoLm91dCA9IG4gKQp2b3RvIDwtIHJub3JtKG4sIG1lYW4gPSA1MCwgc2QgPSAxMCkKCiMgQ3JlaWFtbyB1biBkYXRhZnJhbWUgY29uIGkgZGF0aQpkYXRhIDwtIGRhdGEuZnJhbWUoY29sb3JlLCB2b3RvKQoKIyBNb2RlbGxvIGNvbiB1biBmYXR0b3JlIGNvbiBwacO5IGRpIGR1ZSBsaXZlbGxpCm1vZGVsbG8gPC0gbG0odm90byB+IGNvbG9yZSwgZGF0YSA9IGRhdGEpCgojIFZpc3VhbGl6emlhbW8gaSByaXN1bHRhdGkKc3VtbWFyeShtb2RlbGxvKQpgYGAKCkkgcmlzdWx0YXRpIGluZGljYW5vIGNoZSBpbCBjb2xvcmUgZGVsIHByb2RvdHRvIChyb3NzbyBvIHZlcmRlKSBub24gaGEgdW4gaW1wYXR0byBzaWduaWZpY2F0aXZvIHN1bCB2b3RvLgpMJ2ludGVyY2V0dGEsIGNoZSByYXBwcmVzZW50YSBpbCBjb2xvcmUgIkJsdSwiIMOoIHNpZ25pZmljYXRpdmEsIG1hIGlsIG1vZGVsbG8gbmVsIHN1byBpbnNpZW1lIG5vbiDDqCBtb2x0byBlZmZpY2FjZSBuZWwgc3BpZWdhcmUgbGEgdmFyaWF6aW9uZSBuZWkgdm90aS4KCltUb3JuYSBhbGwnIFtJbmRpY2VdXQoKIyMjIENvbnRyb2xsbyBkZWwgTW9kZWxsbwoKSWwgTW9kZWwgQ2hlY2tpbmcgw6ggdW5hIGZhc2UgY3J1Y2lhbGUgbmVsbCdhbmFsaXNpIHN0YXRpc3RpY2EsIHNwZWNpYWxtZW50ZSBxdWFuZG8gc2kgYWRvdHRhIHVuIG1vZGVsbG8gZGkgcmVncmVzc2lvbmUuCkR1cmFudGUgcXVlc3RhIGZhc2UsIHNpIHZhbHV0YSBzZSBpbCBtb2RlbGxvIHNvZGRpc2ZhIGxlIHByaW5jaXBhbGkgYXNzdW56aW9uaSBkZWkgbW9kZWxsaSBsaW5lYXJpLgpMZSBxdWF0dHJvIGFzc3VuemlvbmkgcHJpbmNpcGFsaSBkYSB2ZXJpZmljYXJlIHNvbm86CgotICAgKipMKippbmVhcml0eSAoTGluZWFyaXTDoCk6IFF1ZXN0YSBhc3N1bnppb25lIGFmZmVybWEgY2hlIGxhIHJpc3Bvc3RhICh2YXJpYWJpbGUgZGlwZW5kZW50ZSkgcHXDsiBlc3NlcmUgc2NyaXR0YSBjb21lIHVuYSBjb21iaW5hemlvbmUgbGluZWFyZSBkZWxsZSB2YXJpYWJpbGkgcHJlZGl0dGl2ZSAodmFyaWFiaWxpIGluZGlwZW5kZW50aSkuIEluIGFsdHJlIHBhcm9sZSwgaWwgbW9kZWxsbyBkb3ZyZWJiZSBlc3NlcmUgaW4gZ3JhZG8gZGkgY2F0dHVyYXJlIGlsIHJhcHBvcnRvIHRyYSBsZSB2YXJpYWJpbGkgaW4gbW9kbyBsaW5lYXJlLCBjb24gdW4gY2VydG8gZ3JhZG8gZGkgcnVtb3JlIHJlc2lkdW8uIExhIGxpbmVhcml0w6AgcHXDsiBlc3NlcmUgdmVyaWZpY2F0YSBhdHRyYXZlcnNvIGdyYWZpY2kgZGkgZGlzcGVyc2lvbmUgbyBncmFmaWNpIHJlc2lkdWkuCi0gICAqKkkqKm5kZXBlbmRlbmNlIChJbmRpcGVuZGVuemEpOiBRdWVzdGEgYXNzdW56aW9uZSByaWNoaWVkZSBjaGUgZ2xpIGVycm9yaSAocmVzaWR1aSkgZGVsIG1vZGVsbG8gc2lhbm8gaW5kaXBlbmRlbnRpIGwndW5vIGRhbGwnYWx0cm8uIENpw7Igc2lnbmlmaWNhIGNoZSBpbCB2YWxvcmUgZGkgZXJyb3JlIHBlciB1bidvc3NlcnZhemlvbmUgbm9uIMOoIGluZmx1ZW56YXRvIGRhbCB2YWxvcmUgZGkgZXJyb3JlIHBlciB1bidhbHRyYSBvc3NlcnZhemlvbmUuIEwnaW5kaXBlbmRlbnphIHB1w7IgZXNzZXJlIHZlcmlmaWNhdGEgb3NzZXJ2YW5kbyBpIGdyYWZpY2kgZGVpIHJlc2lkdWkgaW4gc2VxdWVuemEgdGVtcG9yYWxlIG8gc3BhemlhbGUsIGEgc2Vjb25kYSBkZWwgY29udGVzdG8uCi0gICAqKk4qKm9ybWFsaXR5IChOb3JtYWxpdMOgKTogTCdhc3N1bnppb25lIGRpIG5vcm1hbGl0w6AgcmljaGllZGUgY2hlIGkgcmVzaWR1aSBkZWwgbW9kZWxsbyBzZWd1YW5vIHVuYSBkaXN0cmlidXppb25lIG5vcm1hbGUuIFF1ZXN0byDDqCBpbXBvcnRhbnRlIHBlcmNow6kgbW9sdGUgcHJvY2VkdXJlIHN0YXRpc3RpY2hlIHNpIGJhc2FubyBzdWxsJ2lwb3Rlc2kgZGkgbm9ybWFsaXTDoCBkZWkgcmVzaWR1aS4gTGEgbm9ybWFsaXTDoCBwdcOyIGVzc2VyZSB2ZXJpZmljYXRhIHRyYW1pdGUgZ3JhZmljaSBxdWFudGlsZS1xdWFudGlsZSAoUVEgcGxvdCkgbyBpc3RvZ3JhbW1pIGRlaSByZXNpZHVpLgotICAgKipFKipxdWFsIFZhcmlhbmNlIChWYXJpYW56YSBVbmlmb3JtZSk6IFF1ZXN0YSBhc3N1bnppb25lLCBjaGlhbWF0YSBhbmNoZSBvbW9zY2hlZGFzdGljaXTDoCwgcmljaGllZGUgY2hlIGxhIHZhcmlhbnphIGRlaSByZXNpZHVpIHNpYSBjb3N0YW50ZSBpbiB0dXR0aSBpIGxpdmVsbGkgZGVsbGUgdmFyaWFiaWxpIHByZWRpdHRpdmUuIEluIGFsdHJlIHBhcm9sZSwgbm9uIGRvdnJlYmJlIGVzc2VyY2kgYWxjdW4gbW9kZWxsbyBkaXNjZXJuaWJpbGUgbmVsbGEgdmFyaWFuemEgZGVpIHJlc2lkdWkuIExhIHZhcmlhbnphIHVuaWZvcm1lIHB1w7IgZXNzZXJlIHZlcmlmaWNhdGEgb3NzZXJ2YW5kbyBpIGdyYWZpY2kgZGVpIHJlc2lkdWkgcmlzcGV0dG8gYWkgdmFsb3JpIHByZWRldHRpLgoKUGVyIHZlcmlmaWNhcmUgcXVlc3RlIGFzc3VuemlvbmksIGkgUmVzaWR1YWxzLWJhc2VkIGRpc3BsYXlzIChncmFmaWNpIGJhc2F0aSBzdWkgcmVzaWR1aSkgc29ubyBzcGVzc28gdXRpbGl6emF0aS4KUXVlc3RpIGluY2x1ZG9ubzoKCi0gICBTY2F0dGVycGxvdCBkZWkgcmVzaWR1aTogVW4gZ3JhZmljbyBkZWkgcmVzaWR1aSBjb250cm8gaSB2YWxvcmkgcHJldmlzdGkgbyBsZSB2YXJpYWJpbGkgcHJlZGl0dGl2ZS4gUXVlc3RvIHB1w7Igcml2ZWxhcmUgc2UgYyfDqCB1bmEgc3RydXR0dXJhIG5vbiBsaW5lYXJlIG5laSByZXNpZHVpLgotICAgR3JhZmljbyBkaSBzZXF1ZW56YSB0ZW1wb3JhbGUgZGVpIHJlc2lkdWk6IFV0aWxpenphdG8gcXVhbmRvIGkgZGF0aSBzb25vIHJhY2NvbHRpIG5lbCB0ZW1wbywgcXVlc3RvIGdyYWZpY28gcHXDsiByaXZlbGFyZSBkaXBlbmRlbnplIHRlbXBvcmFsaSBuZWkgcmVzaWR1aS4KLSAgIFFRLXBsb3QgKFF1YW50aWxlLVF1YW50aWxlIHBsb3QpOiBRdWVzdG8gZ3JhZmljbyBjb25mcm9udGEgaSBxdWFudGlsaSBkZWkgcmVzaWR1aSBjb24gcXVlbGxpIGRpIHVuYSBkaXN0cmlidXppb25lIG5vcm1hbGUuIFNlIGkgcHVudGkgZGVsIGdyYWZpY28gc2VndW9ubyB1bmEgbGluZWEgcmV0dGEsIGkgcmVzaWR1aSBzb25vIGFwcHJvc3NpbWF0aXZhbWVudGUgbm9ybWFsaS4KLSAgIElzdG9ncmFtbWEgZGVpIHJlc2lkdWk6IFVuIGlzdG9ncmFtbWEgZGVpIHJlc2lkdWkgcHXDsiBkYXJlIHVuJ2lkZWEgZGVsbGEgbG9ybyBkaXN0cmlidXppb25lIGUgbm9ybWFsaXTDoC4KClJpc3BldHRhcmUgcXVlc3RlIGFzc3Vuemlvbmkgw6ggaW1wb3J0YW50ZSBwZXIgZ2FyYW50aXJlIGNoZSBsZSBzdGltZSBkZWwgbW9kZWxsbyBzaWFubyBhZmZpZGFiaWxpIGUgY2hlIGxlIGNvbmNsdXNpb25pIHNpYW5vIHZhbGlkZS4KU2UgdW5hIG8gcGnDuSBkaSBxdWVzdGUgYXNzdW56aW9uaSBub24gc29ubyBzb2RkaXNmYXR0ZSwgcG90cmViYmVybyBlc3NlcmUgbmVjZXNzYXJpZSBjb3JyZXppb25pIGFsIG1vZGVsbG8gbyBhaSBkYXRpIHN0ZXNzaS4KCltUb3JuYSBhbGwnIFtJbmRpY2VdXQoKIyMjIFRyYW5zZm9ybWF6aW9uaQoKTGUgdHJhc2Zvcm1hemlvbmkgc29ubyB1bmEgdGVjbmljYSB1dGlsaXp6YXRhIG5lbGxhIG1vZGVsbGF6aW9uZSBzdGF0aXN0aWNhIHBlciBtb2RpZmljYXJlIGxlIHJlbGF6aW9uaSB0cmEgdmFyaWFiaWxpIGFsIGZpbmUgZGkgc29kZGlzZmFyZSBtZWdsaW8gbGUgYXNzdW56aW9uaSBkZWwgbW9kZWxsby4KTGUgdHJhc2Zvcm1hemlvbmkgcG9zc29ubyBlc3NlcmUgdXRpbGkgcXVhbmRvIGxlIHJlbGF6aW9uaSB0cmEgbGUgdmFyaWFiaWxpIG5vbiBzb25vIGxpbmVhcmkgbyBxdWFuZG8gbGUgYXNzdW56aW9uaSBkaSBvbW9zY2hlZGFzdGljaXTDoCBvIG5vcm1hbGl0w6AgZGVpIHJlc2lkdWkgbm9uIHNvbm8gc29kZGlzZmF0dGUuCkRpIHNlZ3VpdG8sIGFmZnJvbnRpYW1vIGkgc2VndWVudGkgYXJnb21lbnRpIHJlbGF0aXZpIGFsbGUgdHJhc2Zvcm1hemlvbmk6CgotICAgVmFyaWFuY2UgU3RhYmlsaXppbmcgVHJhbnNmb3JtYXRpb25zIChUcmFzZm9ybWF6aW9uaSBwZXIgU3RhYmlsaXp6YXJlIGxhIFZhcmlhbnphKTogSW4gYWxjdW5pIGNhc2ksIGxhIHZhcmlhbnphIGRlaSBkYXRpIHB1w7IgdmFyaWFyZSBpbiBtb2RvIG5vbiBjb3N0YW50ZSBjb24gaWwgY2FtYmlhcmUgZGVsIHZhbG9yZSBtZWRpby4KICAgIFF1ZXN0byBmZW5vbWVubyDDqCBub3RvIGNvbWUgZXRlcm9zY2hlZGFzdGljaXTDoC4KICAgIExlIHRyYXNmb3JtYXppb25pIHBvc3Nvbm8gZXNzZXJlIHV0aWxpenphdGUgcGVyIHN0YWJpbGl6emFyZSBsYSB2YXJpYW56YSwgcmVuZGVuZG8gbGEgcmVsYXppb25lIHRyYSBpbCB2YWxvcmUgbWVkaW8gZSBsYSB2YXJpYW56YSBwacO5IGNvc3RhbnRlLgogICAgVW4gZXNlbXBpbyBjb211bmUgw6ggbGEgdHJhc2Zvcm1hemlvbmUgZGkgQm94LUNveC4KCi0gICBCb3gtQ294IFRyYW5zZm9ybTogTGEgdHJhc2Zvcm1hemlvbmUgZGkgQm94LUNveCDDqCB1bmEgdGVjbmljYSB1dGlsaXp6YXRhIHBlciBzdGFiaWxpenphcmUgbGEgdmFyaWFuemEgZSByZW5kZXJlIGkgZGF0aSBhcHByb3NzaW1hdGl2YW1lbnRlIG5vcm1hbGkuCiAgICDDiCBkZWZpbml0YSBjb21lOgoKJCQgCnkoXGxhbWJkYSkgPSBcYmVnaW57Y2FzZXN9IFxmcmFjeyh5XlxsYW1iZGEgLSAxKX17XGxhbWJkYX0gJiBcdGV4dHtzZSB9IFxsYW1iZGEgXG5lcSAwIFxcCiAgICBcbG9nKHkpICYgXHRleHR7c2UgfSBcbGFtYmRhID0gMApcZW5ke2Nhc2VzfQokJAoKRG92ZSB5IHNvbm8gaSBkYXRpIG9yaWdpbmFsaSBlIM67IMOoIGlsIHBhcmFtZXRybyBkaSB0cmFzZm9ybWF6aW9uZS4Kw4ggcG9zc2liaWxlIGNhbGNvbGFyZSBpbCB2YWxvcmUgb3R0aW1hbGUgZGkgzrsgY2hlIG1hc3NpbWl6emEgbGEgbm9ybWFsaXTDoCBkZWkgZGF0aS4KCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoTUFTUykKbGlicmFyeShncmlkRXh0cmEpCgojIEdlbmVyYSBkYXRpIGNhc3VhbGkKc2V0LnNlZWQoMTIzKQpkYXRhIDwtIGRhdGEuZnJhbWUoeSA9IHJnYW1tYSgxMDAsIHNoYXBlID0gMiwgc2NhbGUgPSAxKSkKCiMgQXBwbGljYSBsYSB0cmFzZm9ybWF6aW9uZSBkaSBCb3gtQ294CnJlc3VsdCA8LSBib3hjb3goeSB+IDEsIGRhdGEgPSBkYXRhKQpsYW1iZGEgPC0gcmVzdWx0JHhbd2hpY2gubWF4KHJlc3VsdCR5KV0KdHJhbnNmb3JtZWRfZGF0YSA8LSBpZiAobGFtYmRhID09IDApIGxvZyhkYXRhJHkpIGVsc2UgKChkYXRhJHlebGFtYmRhIC0gMSkgLyBsYW1iZGEpCgojIFZpc3VhbGl6emEgaWwgdmFsb3JlIG90dGltYWxlIGRpIGxhbWJkYQpjYXQoIlZhbG9yZSBvdHRpbWFsZSBkaSBsYW1iZGE6ICIsIGxhbWJkYSwgIlxuIikKCiMgQ3JlYSB1biBkYXRhZnJhbWUgY29uIGkgZGF0aSBvcmlnaW5hbGkgZSB0cmFzZm9ybWF0aQpwbG90X2RhdGEgPC0gZGF0YS5mcmFtZShPcmlnaW5hbCA9IGRhdGEkeSwgVHJhbnNmb3JtZWQgPSB0cmFuc2Zvcm1lZF9kYXRhKQoKIyBQbG90dGEgaSBkYXRpIG9yaWdpbmFsaQpwbG90X29yaWdpbmFsIDwtIGdncGxvdChwbG90X2RhdGEsIGFlcyh4ID0gT3JpZ2luYWwpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAwLjUsIGZpbGwgPSAiYmx1ZSIsIGFscGhhID0gMC43KSArCiAgbGFicyh0aXRsZSA9ICJEaXN0cmlidXppb25lIGRlaSBkYXRpIG9yaWdpbmFsaSIpCgojIFBsb3R0YSBpIGRhdGkgdHJhc2Zvcm1hdGkKcGxvdF90cmFuc2Zvcm1lZCA8LSBnZ3Bsb3QocGxvdF9kYXRhLCBhZXMoeCA9IFRyYW5zZm9ybWVkKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMC4xLCBmaWxsID0gImdyZWVuIiwgYWxwaGEgPSAwLjcpICsKICBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1emlvbmUgZGVpIGRhdGkgdHJhc2Zvcm1hdGkiKQoKIyBNb3N0cmEgaSBncmFmaWNpIHN1bGxhIHN0ZXNzYSByaWdhCmdyaWQuYXJyYW5nZShwbG90X29yaWdpbmFsLCBwbG90X3RyYW5zZm9ybWVkLCBuY29sID0gMikKYGBgCgotICAgUG9seW5vbWlhbHMgKFBvbGlub21pKTogTGUgdHJhc2Zvcm1hemlvbmkgcG9saW5vbWlhbGkgY29uc2VudG9ubyBkaSBtb2RlbGxhcmUgcmVsYXppb25pIG5vbiBsaW5lYXJpIHRyYSB2YXJpYWJpbGkuIMOIIHBvc3NpYmlsZSBhZ2dpdW5nZXJlIHRlcm1pbmkgcG9saW5vbWlhbGkgYWwgbW9kZWxsbyBkaSByZWdyZXNzaW9uZSBwZXIgY2F0dHVyYXJlIGN1cnZlIG8gcmVsYXppb25pIHBpw7kgY29tcGxlc3NlLiBBZCBlc2VtcGlvLCBzaSBwb3Nzb25vIHV0aWxpenphcmUgcG9saW5vbWkgZGkgc2Vjb25kbyBncmFkbyBwZXIgbW9kZWxsYXJlIHVuYSByZWxhemlvbmUgcXVhZHJhdGljYSB0cmEgdW5hIHZhcmlhYmlsZSBpbmRpcGVuZGVudGUgZSBsYSB2YXJpYWJpbGUgZGlwZW5kZW50ZS4gTCdhZ2dpdW50YSBkaSB0ZXJtaW5pIHBvbGlub21pYWxpIHB1w7IgbWlnbGlvcmFyZSBsJ2FkYXR0YW1lbnRvIGRlbCBtb2RlbGxvIGFpIGRhdGksIG1hIMOoIGltcG9ydGFudGUgZXZpdGFyZSBkaSBhZ2dpdW5nZXJlIHRyb3BwaSB0ZXJtaW5pIHBvbGlub21pYWxpIHBlciBldml0YXJlIGwnb3ZlcmZpdHRpbmcuCgpgYGB7cn0KIyBNb2RlbGxvIGxpbmVhcmUgY29uIHVuIHRlcm1pbmUgcG9saW5vbWlhbGUgZGkgc2Vjb25kbyBncmFkbwptb2RlbCA8LSBsbSh5IH4geCArIEkoeF4yKSwgZGF0YSA9IGRhdGEpCmBgYAoKLSAgIFRyYW5zZm9ybWF0aW9ucyBvZiBQcmVkaWN0b3IgVmFyaWFibGVzIChUcmFzZm9ybWF6aW9uaSBkZWxsZSBWYXJpYWJpbGkgUHJlZGl0dGl2ZSk6IExlIHRyYXNmb3JtYXppb25pIGRlbGxlIHZhcmlhYmlsaSBwcmVkaXR0aXZlIHNvbm8gdXRpbGl6emF0ZSBwZXIgYWRhdHRhcmUgaSBkYXRpIGluIG1vZG8gY2hlIHNvZGRpc2Zpbm8gbWVnbGlvIGxlIGFzc3VuemlvbmkgZGVsIG1vZGVsbG8uIFF1ZXN0ZSB0cmFzZm9ybWF6aW9uaSBjb2ludm9sZ29ubyBsYSBtb2RpZmljYSBkZWxsZSB2YXJpYWJpbGkgaW5kaXBlbmRlbnRpIHBpdXR0b3N0byBjaGUgZGVsbGEgdmFyaWFiaWxlIGRpcGVuZGVudGUuIFBvc3Nvbm8gZXNzZXJlIHV0aWxpenphdGUgcGVyIHJlbmRlcmUgbGUgcmVsYXppb25pIHRyYSBsZSB2YXJpYWJpbGkgcGnDuSBsaW5lYXJpIG8gcGVyIHN0YWJpbGl6emFyZSBsYSB2YXJpYW56YS4gQWQgZXNlbXBpbywgw6ggcG9zc2liaWxlIGFwcGxpY2FyZSB1bmEgdHJhc2Zvcm1hemlvbmUgbG9nYXJpdG1pY2EgbyB1bmEgcmFkaWNlIHF1YWRyYXRhIGEgdW5hIHZhcmlhYmlsZSBwcmVkaXR0aXZhIHBlciByZW5kZXJsYSBwacO5IGxpbmVhcmUgbmVpIGNvbmZyb250aSBkZWxsYSB2YXJpYWJpbGUgZGlwZW5kZW50ZS4KCmBgYHtyfQojIENyZWlhbW8gZGF0aSBmaXR0aXppCnNldC5zZWVkKDEyMykKWCA8LSBybm9ybSgxMDAsIG1lYW4gPSAxMCwgc2QgPSAyKQpZIDwtIDIgKiBYICsgcm5vcm0oMTAwLCBtZWFuID0gMCwgc2QgPSAxKQoKIyBDcmVpYW1vIHVuIGRhdGFmcmFtZSBjb24gaSBkYXRpCmRhdGEgPC0gZGF0YS5mcmFtZShYLCBZKQoKIyBNb2RlbGxvIGxpbmVhcmUgc2VuemEgdHJhc2Zvcm1hemlvbmUKbW9kZWxfbm9fdHJhbnNmb3JtIDwtIGxtKFkgfiBYLCBkYXRhID0gZGF0YSkKCiMgVmlzdWFsaXp6aWFtbyBpbCBzdW1tYXJ5IGRlbCBtb2RlbGxvIHNlbnphIHRyYXNmb3JtYXppb25lCnN1bW1hcnkobW9kZWxfbm9fdHJhbnNmb3JtKQoKIyBUcmFzZm9ybWlhbW8gbGEgdmFyaWFiaWxlIFggYXBwbGljYW5kbyBpbCBsb2dhcml0bW8KZGF0YSRYX3RyYW5zZm9ybWVkIDwtIGxvZyhkYXRhJFgpCgojIE1vZGVsbG8gbGluZWFyZSBjb24gbGEgdmFyaWFiaWxlIFggdHJhc2Zvcm1hdGEKbW9kZWxfd2l0aF90cmFuc2Zvcm0gPC0gbG0oWSB+IFhfdHJhbnNmb3JtZWQsIGRhdGEgPSBkYXRhKQoKIyBWaXN1YWxpenppYW1vIGlsIHN1bW1hcnkgZGVsIG1vZGVsbG8gY29uIGxhIHZhcmlhYmlsZSBYIHRyYXNmb3JtYXRhCnN1bW1hcnkobW9kZWxfd2l0aF90cmFuc2Zvcm0pCmBgYAoKTGUgdHJhc2Zvcm1hemlvbmkgc29ubyBzdHJ1bWVudGkgcG90ZW50aSBwZXIgYWRhdHRhcmUgaSBtb2RlbGxpIGFpIGRhdGkgaW4gbW9kbyBwacO5IGFjY3VyYXRvIHF1YW5kbyBsZSByZWxhemlvbmkgdHJhIHZhcmlhYmlsaSBub24gc29ubyBsaW5lYXJpIG8gcXVhbmRvIGxlIGFzc3VuemlvbmkgZGVsIG1vZGVsbG8gbm9uIHNvbm8gc29kZGlzZmF0dGUuClR1dHRhdmlhLCDDqCBpbXBvcnRhbnRlIHNjZWdsaWVyZSBjb24gYXR0ZW56aW9uZSBsZSB0cmFzZm9ybWF6aW9uaSBwZXIgZXZpdGFyZSBpbCBzb3ZyYWRhdHRhbWVudG8gZSBnYXJhbnRpcmUgY2hlIGkgcmlzdWx0YXRpIHNpYW5vIGludGVycHJldGFiaWxpLgoKW1Rvcm5hIGFsbCcgW0luZGljZV1dCgojIyMgTXVsdGljb2xsaW5lYXJpdMOgCgpMYSBtdWx0aWNvbGxpbmVhcml0w6Agc2kgdmVyaWZpY2EgcXVhbmRvIGR1ZSBvIHBpw7kgdmFyaWFiaWxpIGluZGlwZW5kZW50aSBpbiB1biBtb2RlbGxvIGRpIHJlZ3Jlc3Npb25lIHNvbm8gZm9ydGVtZW50ZSBjb3JyZWxhdGUgdHJhIGxvcm8uClF1ZXN0YSBjb3JyZWxhemlvbmUgdHJhIGxlIHZhcmlhYmlsaSBpbmRpcGVuZGVudGkgcHXDsiByZW5kZXJlIGRpZmZpY2lsZSBsJ2ludGVycHJldGF6aW9uZSBkZWwgbW9kZWxsbyBlIHBvcnRhcmUgYSBzdGltZSBwb2NvIGFmZmlkYWJpbGkgZGVpIGNvZWZmaWNpZW50aSBkaSByZWdyZXNzaW9uZS4KTGEgcHJlc2VuemEgZGkgbXVsdGljb2xsaW5lYXJpdMOgIHB1w7IgY2F1c2FyZSB1biBhdW1lbnRvIGRlbCBWYXJpYW5jZSBJbmZsYXRpb24gRmFjdG9yIChWSUYpLCB1bmEgbWlzdXJhIGNvbXVuZSB1dGlsaXp6YXRhIHBlciB2YWx1dGFyZSBsYSBtdWx0aWNvbGxpbmVhcml0w6AgdHJhIGxlIHZhcmlhYmlsaSBpbmRpcGVuZGVudGkgaW4gdW4gbW9kZWxsbyBkaSByZWdyZXNzaW9uZS4KVW4gYWx0byBWSUYgcGVyIHVuYSB2YXJpYWJpbGUgaW5kaWNhIGNoZSBxdWVsbGEgdmFyaWFiaWxlIMOoIGZvcnRlbWVudGUgY29ycmVsYXRhIGNvbiBsZSBhbHRyZSB2YXJpYWJpbGkgaW5kaXBlbmRlbnRpIG5lbCBtb2RlbGxvLgoKKipWYXJpYW5jZSBJbmZsYXRpb24gRmFjdG9yOioqCgpJbCBWSUYgZGkgY2lhc2N1bmEgdmFyaWFiaWxlIGluZGlwZW5kZW50ZSDDqCBjYWxjb2xhdG8gY29tZSBpbCByYXBwb3J0byBkZWxsYSB2YXJpYW56YSBkZWxsJ2Vycm9yZSBzdGFuZGFyZCBkZWwgY29lZmZpY2llbnRlIGRpIHJlZ3Jlc3Npb25lIHN0aW1hdG8gcGVyIHF1ZWxsYSB2YXJpYWJpbGUgcmlzcGV0dG8gYWxsYSB2YXJpYW56YSBkZWxsJ2Vycm9yZSBzdGFuZGFyZCBzZSBsYSB2YXJpYWJpbGUgZm9zc2Ugc3RhdGEgY29tcGxldGFtZW50ZSBub24gY29ycmVsYXRhIGFsbGUgYWx0cmUgdmFyaWFiaWxpIGluZGlwZW5kZW50aS4KSW4gZ2VuZXJhbGUsIHVuIFZJRiBzdXBlcmlvcmUgYSA1IG8gMTAgw6ggc3Blc3NvIGNvbnNpZGVyYXRvIHVuIHNlZ25vIGRpIG11bHRpY29sbGluZWFyaXTDoCBzaWduaWZpY2F0aXZhLgoKJCQgClZJRl9pID0gKFheVFgpX3tpKzEsaSsxfV57LTF9Km5zXjJfe1hfaX0gXCBcICBvcHB1cmUgXCBcIFZJRl9pID0gXGZyYWN7MX17MS1SXjJfaX0KJCQKYGBge3J9CiMgTG9hZCB0aGUgbmVjZXNzYXJ5IGxpYnJhcnkKbGlicmFyeShjYXIpCgojIENyZWF0ZSBhIHNhbXBsZSBkYXRhc2V0IHdpdGggbXVsdGlwbGUgcHJlZGljdG9yIHZhcmlhYmxlcwpzZXQuc2VlZCgxMjMpCmRhdGEgPC0gZGF0YS5mcmFtZSgKICBYMSA9IHJub3JtKDEwMCksCiAgWDIgPSBybm9ybSgxMDApLAogIFgzID0gcm5vcm0oMTAwKSwKICBYNCA9IHJub3JtKDEwMCkKKQoKIyBBZGQgYSBkZXBlbmRlbnQgdmFyaWFibGUgKHJlc3BvbnNlKQpkYXRhJFkgPC0gMiAqIGRhdGEkWDEgKyAzICogZGF0YSRYMiArIDEuNSAqIGRhdGEkWDMgKyBybm9ybSgxMDApCgojIEZpdCBhIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsCm1vZGVsIDwtIGxtKFkgfiBYMSArIFgyICsgWDMgKyBYNCwgZGF0YSA9IGRhdGEpCgojIENhbGN1bGF0ZSBWSUYKdmlmX3ZhbHVlcyA8LSB2aWYobW9kZWwpCgojIFByaW50IHRoZSBWSUYgdmFsdWVzCnZpZl92YWx1ZXMKYGBgCgpUdXR0aSBpIHZhbG9yaSBWSUYgc29ubyB2aWNpbmkgYSAxLCBpbCBjaGUgc3VnZ2VyaXNjZSBjaGUgbm9uIGMnw6ggdW5hIGZvcnRlIG11bHRpY29sbGluZWFyaXTDoCB0cmEgbGUgdmFyaWFiaWxpIHByZWRpdHRpdmUgWDEsIFgyLCBYMyBlIFg0LgpRdWVzdG8gw6ggdW4gYnVvbiBzZWdubywgcG9pY2jDqSBzaWduaWZpY2EgY2hlIGxlIHZhcmlhYmlsaSBub24gc29ubyBmb3J0ZW1lbnRlIGNvcnJlbGF0ZSB0cmEgbG9yby4KClZhbG9yaSBWSUYgcGnDuSBlbGV2YXRpIGluZGljYW5vIHVuYSBtdWx0aWNvbGxpbmVhcml0w6AgcGnDuSBmb3J0ZSwgZSB2YWxvcmkgYWwgZGkgc29wcmEgZGkgdW5hIGNlcnRhIHNvZ2xpYSAoYWQgZXNlbXBpbywgVklGIFw+IDUpIHBvc3Nvbm8gc3VnZ2VyaXJlIGxhIG5lY2Vzc2l0w6AgZGkgYWZmcm9udGFyZSBsYSBjb2xsaW5lYXJpdMOgLCBhZCBlc2VtcGlvLCByaW11b3ZlbmRvIHVuYSBkZWxsZSB2YXJpYWJpbGkgcHJlZGl0dGl2ZSBjb3JyZWxhdGUuCgpbVG9ybmEgYWxsJyBbSW5kaWNlXV0KCiMjIyBQdW50aSBJbmZsdWVudGkKCkkgcHVudGkgaW5mbHVlbnRpIHNpIHJpZmVyaXNjb25vIGEgb3NzZXJ2YXppb25pIG5laSBkYXRpIGNoZSBoYW5ubyB1biBpbXBhdHRvIHNpZ25pZmljYXRpdm8gc3VpIHJpc3VsdGF0aSBkaSB1bidhbmFsaXNpIHN0YXRpc3RpY2EsIGNvbWUgdW5hIHJlZ3Jlc3Npb25lIGxpbmVhcmUuClF1ZXN0aSBwdW50aSBwb3Nzb25vIGluZmx1ZW56YXJlIGxhIHN0aW1hIGRlaSBwYXJhbWV0cmkgZGVsIG1vZGVsbG8sIGkgcmVzaWR1aSwgaSB2YWxvcmkgcCwgbCdSLXNxdWFyZWQgZSBhbHRyZSBzdGF0aXN0aWNoZSBkaSByaWxldmFuemEuCkNpIHNvbm8gZGl2ZXJzZSBtZXRyaWNoZSB1dGlsaXp6YXRlIHBlciBpZGVudGlmaWNhcmUgaSBwdW50aSBpbmZsdWVudGksIHRyYSBjdWkgU3RhbmRhcmRpemVkIFJlc2lkdWFscywgU3R1ZGVudGl6ZWQgUmVzaWR1YWxzIGUgQ29vaydzIERpc3RhbmNlLgoKLSAgIFN0YW5kYXJkaXplZCBSZXNpZHVhbHMgKFJlc2lkdWkgU3RhbmRhcmRpenphdGkpOiBRdWVzdGkgc29ubyBpIHJlc2lkdWkgZGl2aXNpIHBlciBsYSBkZXZpYXppb25lIHN0YW5kYXJkIGRlaSByZXNpZHVpLiBVbiByZXNpZHVvIHN0YW5kYXJkaXp6YXRvIMOoIHVuYSBtaXN1cmEgZGkgcXVhbnRvIHVuIHB1bnRvIGRhdG8gc2kgZGlzY29zdGkgZGFsbGEgbGluZWEgZGkgcmVncmVzc2lvbmUgaW4gdGVybWluaSBkaSBkZXZpYXppb25pIHN0YW5kYXJkLiBJIHB1bnRpIGNvbiByZXNpZHVpIHN0YW5kYXJkaXp6YXRpIG1vbHRvIGdyYW5kaSAocG9zaXRpdmkgbyBuZWdhdGl2aSkgc29ubyBjb25zaWRlcmF0aSBpbmZsdWVudGkuCi0gICBTdHVkZW50aXplZCBSZXNpZHVhbHMgKFJlc2lkdWkgU3R1ZGVudGl6emF0aSk6IFF1ZXN0aSBzb25vIGkgcmVzaWR1aSBkaXZpc2kgcGVyIHVuYSBzdGltYSBkZWxsYSBkZXZpYXppb25lIHN0YW5kYXJkIGRlbGwnZXJyb3JlIHJlc2lkdW8uIEkgcmVzaWR1aSBzdHVkZW50aXp6YXRpIHNvbm8gdXRpbGl6emF0aSBwZXIgdmFsdXRhcmUgcXVhbnRvIHVuIHB1bnRvIGRhdG8gc2lhIGluZmx1ZW50ZSBjb25zaWRlcmFuZG8gbCdlZmZldHRvIGRlbGxlIGFsdHJlIG9zc2VydmF6aW9uaSBuZWwgZGF0YXNldC4gSSBwdW50aSBjb24gcmVzaWR1aSBzdHVkZW50aXp6YXRpIHNpZ25pZmljYXRpdmFtZW50ZSBncmFuZGkgaW4gdmFsb3JlIGFzc29sdXRvIHNvbm8gY29uc2lkZXJhdGkgaW5mbHVlbnRpLgotICAgQ29vaydzIERpc3RhbmNlIChEaXN0YW56YSBkaSBDb29rKTogQ29vaydzIERpc3RhbmNlIMOoIHVuYSBtZXRyaWNhIGNoZSBjb21iaW5hIGwnZWZmZXR0byBkaSB1biBwdW50byBzdWkgcGFyYW1ldHJpIGRlbCBtb2RlbGxvIGUgaWwgc3VvIGVmZmV0dG8gc3VpIHJlc2lkdWkuIEkgcHVudGkgY29uIENvb2sncyBEaXN0YW5jZSBtb2x0byBncmFuZGkgc29ubyBjb25zaWRlcmF0aSBpbmZsdWVudGkuIENvb2sncyBEaXN0YW5jZSDDqCBzcGVzc28gdXRpbGl6emF0byBwZXIgaWRlbnRpZmljYXJlIHB1bnRpIGNoZSwgc2Ugcmltb3NzaSwgYXZyZWJiZXJvIHVuIGltcGF0dG8gc2lnbmlmaWNhdGl2byBzdWkgcmlzdWx0YXRpIGRlbCBtb2RlbGxvLgoKTmVsIGNvbnRlc3RvIGRlbGxhIHJlZ3Jlc3Npb25lLCBpIHB1bnRpIGluZmx1ZW50aSBwb3Nzb25vIGRlcml2YXJlIGRhIG91dGxpZXIgbmVpIGRhdGksIGRhdGkgZXJyYXRpIG8gcHVudGkgY2hlIGluZmx1ZW56YW5vIG5vdGV2b2xtZW50ZSBsYSBzdGltYSBkZWkgcGFyYW1ldHJpLgpJZGVudGlmaWNhcmUgZSB0cmF0dGFyZSBpIHB1bnRpIGluZmx1ZW50aSDDqCBpbXBvcnRhbnRlIHBlciBnYXJhbnRpcmUgY2hlIGlsIG1vZGVsbG8gZGkgcmVncmVzc2lvbmUgc2lhIGFmZmlkYWJpbGUgZSByYXBwcmVzZW50aSBhY2N1cmF0YW1lbnRlIGkgZGF0aS4KTGEgcmltb3ppb25lIGRpIHB1bnRpIGluZmx1ZW50aSBwdcOyIG1pZ2xpb3JhcmUgbGEgYm9udMOgIGRpIGFkYXR0YW1lbnRvIGRlbCBtb2RlbGxvIGUgbCdhY2N1cmF0ZXp6YSBkZWxsZSBwcmV2aXNpb25pLgoKYGBge3J9CiMgQ2FyaWNoaWFtbyBpbCBkYXRhc2V0IGRpIGVzZW1waW8KZGF0YShtdGNhcnMpCgojIEFkYXR0aWFtbyB1biBtb2RlbGxvIGRpIHJlZ3Jlc3Npb25lIGxpbmVhcmUKbW9kZWwgPC0gbG0obXBnIH4gd3QgKyBocCwgZGF0YSA9IG10Y2FycykKCiMgQ2FsY29saWFtbyBpIHJlc2lkdWkgc3RhbmRhcmRpenphdGkKc3RhbmRhcmRpemVkX3Jlc2lkdWFscyA8LSByc3RhbmRhcmQobW9kZWwpCgojIElkZW50aWZpY2hpYW1vIGkgcHVudGkgaW5mbHVlbnRpIGJhc2F0aSBzdWkgcmVzaWR1aSBzdGFuZGFyZGl6emF0aQppbmZsdWVudGlhbF9wb2ludHMgPC0gd2hpY2goYWJzKHN0YW5kYXJkaXplZF9yZXNpZHVhbHMpID4gMikKCiMgVmlzdWFsaXp6aWFtbyBnbGkgaW5kaWNpIGRlaSBwdW50aSBpbmZsdWVudGkKY2F0KCJQdW50aSBpbmZsdWVudGkgYmFzYXRpIHN1aSByZXNpZHVpIHN0YW5kYXJkaXp6YXRpOiIsIGluZmx1ZW50aWFsX3BvaW50cywgIlxuIikKCiMgQ2FsY29saWFtbyBDb29rJ3MgRGlzdGFuY2UKY29va19kaXN0YW5jZSA8LSBjb29rcy5kaXN0YW5jZShtb2RlbCkKCiMgSWRlbnRpZmljaGlhbW8gaSBwdW50aSBpbmZsdWVudGkgYmFzYXRpIHN1IENvb2sncyBEaXN0YW5jZQppbmZsdWVudGlhbF9wb2ludHNfY29vayA8LSB3aGljaChjb29rX2Rpc3RhbmNlID4gNCAvIGxlbmd0aChjb29rX2Rpc3RhbmNlKSkKCiMgVmlzdWFsaXp6aWFtbyBnbGkgaW5kaWNpIGRlaSBwdW50aSBpbmZsdWVudGkgYmFzYXRpIHN1IENvb2sncyBEaXN0YW5jZQpjYXQoIlB1bnRpIGluZmx1ZW50aSBiYXNhdGkgc3UgQ29vaydzIERpc3RhbmNlOiIsIGluZmx1ZW50aWFsX3BvaW50c19jb29rLCAiXG4iKQoKcGFyKG1mcm93ID0gYygxLDIpKQojIEdyYWZpY28gZGVpIHB1bnRpIGNvbiBldmlkZW56aWF6aW9uZSBkZWkgcHVudGkgaW5mbHVlbnRpCnBsb3QobXRjYXJzJHd0LCBtdGNhcnMkbXBnLCBwY2ggPSAxNiwgbWFpbiA9ICJTY2F0dGVyIHBsb3QgY29uIFB1bnRpIEluZmx1ZW50aSAoU3RhbiBlIFN0dWQpIiwKICAgICB4bGFiID0gIlBlc28gKHd0KSIsIHlsYWIgPSAiTWlnbGlhIHBlciBnYWxsb25lIChtcGcpIikKcG9pbnRzKG10Y2FycyR3dFtpbmZsdWVudGlhbF9wb2ludHNdLCBtdGNhcnMkbXBnW2luZmx1ZW50aWFsX3BvaW50c10sIHBjaCA9IDE2LCBjb2wgPSAicmVkIiwgY2V4ID0gMS41KQoKCnBsb3QobXRjYXJzJHd0LCBtdGNhcnMkbXBnLCBwY2ggPSAxNiwgbWFpbiA9ICJTY2F0dGVyIHBsb3QgY29uIFB1bnRpIEluZmx1ZW50aSAoQ29vaykiLAogICAgIHhsYWIgPSAiUGVzbyAod3QpIiwgeWxhYiA9ICJNaWdsaWEgcGVyIGdhbGxvbmUgKG1wZykiKQpwb2ludHMobXRjYXJzJHd0W2luZmx1ZW50aWFsX3BvaW50c19jb29rXSwgbXRjYXJzJG1wZ1tpbmZsdWVudGlhbF9wb2ludHNfY29va10sIHBjaCA9IDE2LCBjb2wgPSAicmVkIiwgY2V4ID0gMS41KQoKYGBgCgoqKkxldmVyYWdlOioqCgpJbCAiTGV2ZXJhZ2UiIMOoIHVuYSBtaXN1cmEgdXRpbGl6emF0YSBuZWxsJ2FuYWxpc2kgZGVpIGRhdGkgc3RhdGlzdGljaSBwZXIgaWRlbnRpZmljYXJlIHB1bnRpIGluZmx1ZW50aSBvIG9zc2VydmF6aW9uaSBhdGlwaWNoZSBpbiB1biBtb2RlbGxvIGRpIHJlZ3Jlc3Npb25lLgpRdWVzdGEgbWlzdXJhIHZhbHV0YSBxdWFudG8gdW4nb3NzZXJ2YXppb25lIHB1w7IgaW5mbHVlbnphcmUgaSByaXN1bHRhdGkgZGVsIG1vZGVsbG8sIGluIHBhcnRpY29sYXJlIGkgY29lZmZpY2llbnRpIGRpIHJlZ3Jlc3Npb25lLgpJbCBsZXZlcmFnZSDDqCBjYWxjb2xhdG8gc3VsbGEgYmFzZSBkZWxsZSB2YXJpYWJpbGkgcHJlZGl0dGl2ZSBlIHB1w7IgZXNzZXJlIHV0aWxpenphdG8gcGVyIGlkZW50aWZpY2FyZSBsZSBvc3NlcnZhemlvbmkgY2hlIGhhbm5vIHVuIGltcGF0dG8gc2lnbmlmaWNhdGl2byBzdWwgbW9kZWxsby4KCklkZW50aWZpY2F6aW9uZSBkZWkgcHVudGkgaW5mbHVlbnRpOiBJIHB1bnRpIGNvbiB1biB2YWxvcmUgZGkgbGV2ZXJhZ2Ugc2lnbmlmaWNhdGl2YW1lbnRlIHBpw7kgYWx0byBkZWdsaSBhbHRyaSBzb25vIHF1ZWxsaSBjaGUgcG9zc29ubyBpbmZsdWVuemFyZSBub3Rldm9sbWVudGUgaWwgbW9kZWxsby4KUHVvaSBzdGFiaWxpcmUgdW5hIHNvZ2xpYSBhcmJpdHJhcmlhIG8gdXRpbGl6emFyZSBtZXRvZGkgc3RhdGlzdGljaSBwZXIgZGV0ZXJtaW5hcmUgcXVhbGkgcHVudGkgc29ubyBpbmZsdWVudGkuCkFkIGVzZW1waW8sIGkgcHVudGkgY29uIGxldmVyYWdlIHN1cGVyaW9yZSBhIDIgdm9sdGUgbGEgbWVkaWEgcG9zc29ubyBlc3NlcmUgY29uc2lkZXJhdGkgaW5mbHVlbnRpLgoKRXNhbWUgZGVpIHB1bnRpIGluZmx1ZW50aTogVW5hIHZvbHRhIGlkZW50aWZpY2F0aSBpIHB1bnRpIGluZmx1ZW50aSwgw6ggcG9zc2liaWxlIGVzYW1pbmFybGkgdWx0ZXJpb3JtZW50ZSBwZXIgZGV0ZXJtaW5hcmUgc2Ugc29ubyBlZmZldHRpdmFtZW50ZSBvdXRsaWVycyBvIGVycm9yaSBkaSBtaXN1cmF6aW9uZS4KUG90cmVzdGkgdm9sZXIgZXNhbWluYXJlIGxlIG9zc2VydmF6aW9uaSBjb24gZWxldmF0ZSBkaWZmZXJlbnplIHRyYSBpIHZhbG9yaSBvc3NlcnZhdGkgZSBxdWVsbGkgcHJldmlzdGkgZGFsIG1vZGVsbG8uCgrDiCBpbXBvcnRhbnRlIG5vdGFyZSBjaGUgbGEgcmltb3ppb25lIGRlaSBwdW50aSBpbmZsdWVudGkgZG92cmViYmUgZXNzZXJlIGVmZmV0dHVhdGEgY29uIGNhdXRlbGEgZSBzb2xvIHNlIGMnw6ggdW5hIGdpdXN0aWZpY2F6aW9uZSB2YWxpZGEuCkluIGFsY3VuaSBjYXNpLCBwb3RyZXN0aSBzY2VnbGllcmUgZGkgbWFudGVuZXJlIGkgcHVudGkgaW5mbHVlbnRpIG5lbCBtb2RlbGxvIHNlIHJpdGllbmkgY2hlIHJhcHByZXNlbnRpbm8gaW5mb3JtYXppb25pIHNpZ25pZmljYXRpdmUgbyBzZSBoYW5ubyB1bmEgc3BpZWdhemlvbmUgcGxhdXNpYmlsZS4KCmBgYHtyfQojIEdlbmVyaWFtbyBkYXRpIGNhc3VhbGkKc2V0LnNlZWQoMTIzKQpuIDwtIDEwMAp4IDwtIHJub3JtKG4pCnkgPC0gMiAqIHggKyBybm9ybShuKQoKIyBBZGF0dGlhbW8gdW4gbW9kZWxsbyBkaSByZWdyZXNzaW9uZSBsaW5lYXJlCm1vZGVsIDwtIGxtKHkgfiB4KQoKIyBDYWxjb2xpYW1vIGkgdmFsb3JpIGRpIGxldmVyYWdlCmxldmVyYWdlIDwtIGhhdHZhbHVlcyhtb2RlbCkKCiMgSWRlbnRpZmljaGlhbW8gaSBwdW50aSBpbmZsdWVudGkKaW5mbF9wb2ludHMgPC0gd2hpY2gobGV2ZXJhZ2UgPiAyICogbWVhbihsZXZlcmFnZSkpCgojIFZpc3VhbGl6emlhbW8gaSBwdW50aSBpbmZsdWVudGkKcHJpbnQoaW5mbF9wb2ludHMpCgpwYXIobWZyb3cgPSBjKDEsMikpCiMgUGxvdCBkZWwgZ3JhZmljbwpwbG90KHgsIHkpCnBvaW50cyh4W2luZmxfcG9pbnRzXSwgeVtpbmZsX3BvaW50c10sIGNvbCA9ICJibHVlIiwgcGNoID0gMTkpCgojIFBsb3QgZGVsIExldmVyYWdlCnBsb3QoeCwgbGV2ZXJhZ2UpCnBvaW50cyh4W2luZmxfcG9pbnRzXSwgbGV2ZXJhZ2VbaW5mbF9wb2ludHNdLCBjb2wgPSAiYmx1ZSIsIHBjaCA9IDE5KQpgYGAKCk5vdGEgY2hlIG5lbGwnZXNlbXBpbyBhYmJpYW1vIHV0aWxpenphdG8gdW5hIHNvZ2xpYSBkaSBsZXZlcmFnZSBhcmJpdHJhcmlhICgyIHZvbHRlIGxhIG1lZGlhKSBwZXIgaWRlbnRpZmljYXJlIGkgcHVudGkgaW5mbHVlbnRpLgpJbiB1bidhcHBsaWNhemlvbmUgcHJhdGljYSwgw6ggY29uc2lnbGlhYmlsZSBjb25zaWRlcmFyZSBsYSBzb2dsaWEgaW4gYmFzZSBhbCBjb250ZXN0byBkZWwgcHJvYmxlbWEgZSBhbGwnYW5hbGlzaSBkZWkgZGF0aS4KCltUb3JuYSBhbGwnIFtJbmRpY2VdXQoKIyBNb2RlbGxpIExpbmVhcmkgR2VuZXJhbGl6emF0aSB7I21vZGVsbGktbGluZWFyaS1nZW5lcmFsaXp6YXRpLWdsbX0KCkkgR0xNIGVzdGVuZG9ubyBpbCBmcmFtZXdvcmsgZGVsbGEgcmVncmVzc2lvbmUgbGluZWFyZSBwZXIgZ2VzdGlyZSB1bidhbXBpYSBnYW1tYSBkaSBkaXN0cmlidXppb25pIGRlaSBkYXRpIGUgdGlwb2xvZ2llIGRpIHJpc3Bvc3RlLgpBIGRpZmZlcmVuemEgZGVsbGEgcmVncmVzc2lvbmUgbGluZWFyZSB0cmFkaXppb25hbGUsIGkgR0xNIHBvc3Nvbm8gYWNjb21vZGFyZSBkaXN0cmlidXppb25pIGRpIGVycm9yaSBub24gbm9ybWFsaSBlIG1vZGVsbGFyZSByZWxhemlvbmkgdHJhIHByZWRpdHRvcmkgZSByaXNwb3N0ZSBhdHRyYXZlcnNvIHVuYSBmdW56aW9uZSBkaSBjb2xsZWdhbWVudG8uCgpVbiBHTE0gw6ggY2FyYXR0ZXJpenphdG8gZGEgdHJlIGNvbXBvbmVudGkgcHJpbmNpcGFsaToKCjEuICAqKkNvbXBvbmVudGUgQ2FzdWFsZSAoRGlzdHJpYnV6aW9uZSk6KiogTGEgdmFyaWFiaWxlIGRpIHJpc3Bvc3RhICRZJCBzZWd1ZSB1bmEgZGlzdHJpYnV6aW9uZSBkaSBwcm9iYWJpbGl0w6AgZGFsbGEgZmFtaWdsaWEgZXNwb25lbnppYWxlLCBjaGUgaW5jbHVkZSBkaXN0cmlidXppb25pIGNvbXVuaSBjb21lIG5vcm1hbGUsIGJpbm9taWFsZSBlIGRpIFBvaXNzb24uCgoyLiAgKipDb21wb25lbnRlIFNpc3RlbWF0aWNhIChQcmVkaXR0b3JlIExpbmVhcmUpOioqIExhIHJlbGF6aW9uZSB0cmEgaSBwcmVkaXR0b3JpIGUgaWwgdmFsb3JlIGF0dGVzbyBkZWxsYSByaXNwb3N0YSDDqCBlc3ByZXNzYSBhdHRyYXZlcnNvIHVuIHByZWRpdHRvcmUgbGluZWFyZSAoJFxldGEkKS4KICAgIElsIHByZWRpdHRvcmUgbGluZWFyZSDDqCB1bmEgY29tYmluYXppb25lIGRlaSBwcmVkaXR0b3JpLCBvZ251bm8gbW9sdGlwbGljYXRvIHBlciB1biBwYXJhbWV0cm8sIGUgc2kgY29sbGVnYSBhbGxhIG1lZGlhIGRlbGxhIHJpc3Bvc3RhIGF0dHJhdmVyc28gdW5hIGZ1bnppb25lIGRpIGNvbGxlZ2FtZW50by4KCjMuICAqKkZ1bnppb25lIGRpIENvbGxlZ2FtZW50bzoqKiBMYSBmdW56aW9uZSBkaSBjb2xsZWdhbWVudG8gKCRnKFxtdSkkKSBzdGFiaWxpc2NlIGlsIGNvbGxlZ2FtZW50byB0cmEgaWwgcHJlZGl0dG9yZSBsaW5lYXJlIGUgbGEgbWVkaWEgZGVsbGEgcmlzcG9zdGEuCiAgICBUcmFzZm9ybWEgbGEgc2NhbGEgZGVsbGEgdmFyaWFiaWxlIGRpIHJpc3Bvc3RhIGUgYXNzaWN1cmEgY2hlIGlsIHByZWRpdHRvcmUgbGluZWFyZSBjb3ByYSBsJ2ludGVyYSBsaW5lYSByZWFsZS4KICAgIExlIGZ1bnppb25pIGRpIGNvbGxlZ2FtZW50byBjb211bmkgaW5jbHVkb25vIGxvZ2l0LCBwcm9iaXQgZSBpZGVudGl0w6AuCgpMYSBmb3JtYSBnZW5lcmFsZSBkaSB1biBHTE0gcHXDsiBlc3NlcmUgcmFwcHJlc2VudGF0YSBjb21lIHNlZ3VlOgoKJCQgZyhcbXUpID0gWFxiZXRhICQkCgpEb3ZlOgoKLSAgICRnKFxtdSkkIMOoIGxhIGZ1bnppb25lIGRpIGNvbGxlZ2FtZW50by4KLSAgICRcbXUkIMOoIGlsIHZhbG9yZSBhdHRlc28gZGVsbGEgdmFyaWFiaWxlIGRpIHJpc3Bvc3RhLgotICAgJFgkIMOoIGxhIG1hdHJpY2UgZGVpIHByZWRpdHRvcmkuCi0gICAkXGJldGEkIMOoIGlsIHZldHRvcmUgZGVpIGNvZWZmaWNpZW50aS4KCioqRXNlbXBpOioqCgoxLiAgKipSZWdyZXNzaW9uZSBMb2dpc3RpY2EgQmluYXJpYToqKgoKICAgIC0gICAqKkRpc3RyaWJ1emlvbmU6KiogQmlub21pYWxlCiAgICAtICAgKipGdW56aW9uZSBkaSBDb2xsZWdhbWVudG86KiogTG9naXQgKGxvZy1yYXBwb3J0aSBkaSBwcm9iYWJpbGl0w6ApCiAgICAtICAgKipFcXVhemlvbmU6KiogJFx0ZXh0e2xvZ2l0fShcbXUpID0gWFxiZXRhJAoKICAgICoqRGVzY3JpemlvbmU6KiogTGEgZnVuemlvbmUgZGkgY29sbGVnYW1lbnRvIGxvZ2l0IHRyYXNmb3JtYSBsYSBwcm9iYWJpbGl0w6AgZGkgc3VjY2Vzc28gKCRcbXUkKSBpbiB1biBwcmVkaXR0b3JlIGxpbmVhcmUuCiAgICBJbiBxdWVzdG8gY2FzbywgaWwgbW9kZWxsbyBsb2dpc3RpYyBkZXNjcml2ZSBjb21lIGxhIGxvZy1vZGRzIGRlbGxhIHByb2JhYmlsaXTDoCBkaSBzdWNjZXNzbyBzaWEgbGluZWFyZSByaXNwZXR0byBhaSBwcmVkaXR0b3JpLgoKMi4gICoqUmVncmVzc2lvbmUgZGkgUG9pc3NvbjoqKgoKICAgIC0gICAqKkRpc3RyaWJ1emlvbmU6KiogUG9pc3NvbgogICAgLSAgICoqRnVuemlvbmUgZGkgQ29sbGVnYW1lbnRvOioqIExvZwogICAgLSAgICoqRXF1YXppb25lOioqICRcbG9nKFxtdSkgPSBYXGJldGEkCgogICAgKipEZXNjcml6aW9uZToqKiBDb24gbGEgZnVuemlvbmUgZGkgY29sbGVnYW1lbnRvIGxvZ2FyaXRtaWNvLCBpbCBtb2RlbGxvIGRpIFBvaXNzb24gcHXDsiBnZXN0aXJlIGRhdGkgZGkgY29udGVnZ2lvLCBwb2ljaMOpIGNvbm5ldHRlIGlsIGxvZ2FyaXRtbyBuYXR1cmFsZSBkZWwgdmFsb3JlIGF0dGVzbyAoJFxtdSQpIGEgdW4gcHJlZGl0dG9yZSBsaW5lYXJlLgoKMy4gICoqUmVncmVzc2lvbmUgR2FtbWE6KioKCiAgICAtICAgKipEaXN0cmlidXppb25lOioqIEdhbW1hCiAgICAtICAgKipGdW56aW9uZSBkaSBDb2xsZWdhbWVudG86KiogSW52ZXJzbwogICAgLSAgICoqRXF1YXppb25lOioqICRcZnJhY3sxfXtcbXV9ID0gWFxiZXRhJAoKICAgICoqRGVzY3JpemlvbmU6KiogTGEgZnVuemlvbmUgZGkgY29sbGVnYW1lbnRvIGludmVyc2EgaW4gdW4gbW9kZWxsbyBnYW1tYSDDqCBhcHByb3ByaWF0YSBxdWFuZG8gc2kgbW9kZWxsYW5vIHZhcmlhYmlsaSBjb24gZGlzdHJpYnV6aW9uaSBhIGNvZGEgcGVzYW50ZS4KICAgIENvbGxlZ2EgbCdpbnZlcnNvIGRlbCB2YWxvcmUgYXR0ZXNvICgkXG11JCkgYSB1biBwcmVkaXR0b3JlIGxpbmVhcmUuCgojIyMgRGV2aWFuemEKCkxhIGRldmlhbnphIMOoIHVuYSBtaXN1cmEgZGVsbGEgZGlzY3JlcGFuemEgdHJhIGlsIG1vZGVsbG8gc3RhdGlzdGljbyBlIGkgZGF0aSBvc3NlcnZhdGkgbmVpIEdMTS4KSW4gZ2VuZXJhbGUsIGxhIGRldmlhbnphIMOoIHV0aWxpenphdGEgcGVyIGNvbmZyb250YXJlIG1vZGVsbGkgYWx0ZXJuYXRpdmkgZSB2YWx1dGFyZSBxdWFudG8gYmVuZSB1biBtb2RlbGxvIHNpIGFkYXR0YSBhaSBkYXRpLgpOZWwgY29udGVzdG8gZGVpIEdMTSwgbGEgZGV2aWFuemEgw6ggcGFydGljb2xhcm1lbnRlIHNpZ25pZmljYXRpdmEgcGVyY2jDqSB0aWVuZSBjb250byBkZWxsZSBzcGVjaWZpY2hlIGRpc3RyaWJ1emlvbmkgZGVsbGUgdmFyaWFiaWxpIGRpIHJpc3Bvc3RhLgoKTGEgZGV2aWFuemEgc2kgY2FsY29sYSBjb25mcm9udGFuZG8gaWwgbW9kZWxsbyBmaXR0ZWQgKHByZXZpc3RvKSBjb24gdW4gbW9kZWxsbyBudWxsLCBzcGVzc28gbm90byBjb21lIG1vZGVsbG8gbnVsbCBkaSBzYXR1cmF6aW9uZS4KSWwgbW9kZWxsbyBudWxsIHJhcHByZXNlbnRhIGwnaXBvdGVzaSBjaGUgdHV0dGkgaSBwYXJhbWV0cmkgZGVsIG1vZGVsbG8gc2lhbm8gdWd1YWxpIGEgemVybywgaW5kaWNhbmRvIGwnYXNzZW56YSBkaSBlZmZldHRpIHByZWRpdHRvcmkuCkxhIGRldmlhbnphIMOoIGRhdGEgZGFsbGEgc2VndWVudGUgZm9ybXVsYToKCiQkIEQgPSAyIFx0aW1lcyBcbGVmdCggXGVsbChcaGF0e1xiZXRhfSkgLSBcZWxsKFxiZXRhXzApIFxyaWdodCkgJCQKCkRvdmU6CgotICAgJFxlbGwoXGhhdHtcYmV0YX0pJCDDqCBpbCBsb2ctbGlrZWxpaG9vZCBkZWwgbW9kZWxsbyBmaXR0ZWQuCi0gICAkXGVsbChcYmV0YV8wKSQgw6ggaWwgbG9nLWxpa2VsaWhvb2QgZGVsIG1vZGVsbG8gbnVsbC4KLSAgICREJCDDqCBsYSBkZXZpYW56YS4KClBvaWNow6kgaSBHTE0gdXRpbGl6emFubyBsYSBmYW1pZ2xpYSBlc3BvbmVuemlhbGUgZGkgZGlzdHJpYnV6aW9uaSwgbGEgZGV2aWFuemEgYXNzdW1lIHVuYSBmb3JtYSBzcGVjaWZpY2EgcGVyIGRpdmVyc2UgZGlzdHJpYnV6aW9uaS4KCioqRm9ybXVsZSBkZWxsYSBWZXJvc2ltaWdsaWFuemE6KioKCjEuICAqKk1vZGVsbG8gTm9ybWFsZToqKiBMYSB2ZXJvc2ltaWdsaWFuemEgbmVsIGNhc28gZGkgdW5hIGRpc3RyaWJ1emlvbmUgbm9ybWFsZSDDqCBkZWZpbml0YSBkYWxsYSBkZW5zaXTDoCBkaSBwcm9iYWJpbGl0w6AgZGVsbGEgZGlzdHJpYnV6aW9uZSBub3JtYWxlLgogICAgUGVyIHVuYSBzaW5nb2xhIG9zc2VydmF6aW9uZSwgbGEgZm9ybXVsYSDDqDogJCQgTCh5X2kgfCBcbXVfaSwgXHNpZ21hXjIpID0gXGZyYWN7MX17XHNxcnR7MlxwaVxzaWdtYV4yfX0gXGV4cFxsZWZ0KC1cZnJhY3soeV9pIC0gXG11X2kpXjJ9ezJcc2lnbWFeMn1ccmlnaHQpICQkCgogICAgRG92ZToKCiAgICAtICAgJHlfaSQgw6ggbCdvc3NlcnZhemlvbmUgaS1lc2ltYS4KICAgIC0gICAkXG11X2kkIMOoIGlsIHZhbG9yZSBhdHRlc28gZGVsbGEgdmFyaWFiaWxlIGRpIHJpc3Bvc3RhIGktZXNpbWEuCiAgICAtICAgJFxzaWdtYV4yJCDDqCBsYSB2YXJpYW56YS4KCjIuICAqKk1vZGVsbG8gZGkgUG9pc3NvbjoqKiBMYSB2ZXJvc2ltaWdsaWFuemEgbmVsIGNhc28gZGkgdW5hIGRpc3RyaWJ1emlvbmUgZGkgUG9pc3NvbiDDqCBkZWZpbml0YSBjb21lIHNlZ3VlOiAkJCBMKHlfaSB8IFxsYW1iZGFfaSkgPSBcZnJhY3tcbGFtYmRhX2lee3lfaX0gXGV4cCgtXGxhbWJkYV9pKX17eV9pIX0gJCQKCiAgICBEb3ZlOgoKICAgIC0gICAkeV9pJCDDqCBsJ29zc2VydmF6aW9uZSBpLWVzaW1hLgogICAgLSAgICRcbGFtYmRhX2kkIMOoIGlsIHZhbG9yZSBhdHRlc28gZGVsbGEgdmFyaWFiaWxlIGRpIHJpc3Bvc3RhIGktZXNpbWEuCgoqKkludGVycHJldGF6aW9uZToqKiBMYSBkZXZpYW56YSBwdcOyIGVzc2VyZSBpbnRlcnByZXRhdGEgY29tZSB1bmEgbWlzdXJhIGRlbGxhIGRpc2NyZXBhbnphIHRyYSBpbCBtb2RlbGxvIGZpdHRlZCBlIGlsIG1vZGVsbG8gbnVsbC4KVW4gdmFsb3JlIGRpIGRldmlhbnphIHBpw7kgYmFzc28gaW5kaWNhIHVuYSBtaWdsaW9yZSBhZGF0dGFiaWxpdMOgIGRlbCBtb2RlbGxvIGFpIGRhdGkuClR1dHRhdmlhLCBwb2ljaMOpIGxhIGRldmlhbnphIMOoIHVuYSBtaXN1cmEgYXNzb2x1dGEsIMOoIHNwZXNzbyB1dGlsaXp6YXRvIGlsIGNvbmNldHRvIGRpIGRldmlhbnphIHJlc2lkdWEsIGNoZSDDqCBsYSBkZXZpYW56YSBkaXZpc2EgcGVyIGlsIG51bWVybyBkaSBncmFkaSBkaSBsaWJlcnTDoCBkZWwgbW9kZWxsby4KUXVlc3RvIGNvbnNlbnRlIHVuIGNvbmZyb250byBwacO5IGVxdW8gdHJhIG1vZGVsbGkgY29uIGRpZmZlcmVudGkgY29tcGxlc3NpdMOgLgoKKipDb250cmlidXRvIGRlbGxlIENvbXBvbmVudGk6KiogTmVsIGNvbnRlc3RvIGRlaSBHTE0sIGxhIGRldmlhbnphIMOoIHNwZXNzbyBzY29tcG9zdGEgaW4gdHJlIGNvbXBvbmVudGkgcHJpbmNpcGFsaToKCjEuICAqKk1vZGVsbG8gRml0dGVkIERldmlhbmNlICgqKiREX3tcdGV4dHtmaXR0ZWR9fSQpOiBNaXN1cmEgbGEgZGlzY3JlcGFuemEgdHJhIGlsIG1vZGVsbG8gZml0dGVkIGUgaSBkYXRpIG9zc2VydmF0aS4KCjIuICAqKk51bGwgRGV2aWFuY2UgKCoqJERfe1x0ZXh0e251bGx9fSQpOiBNaXN1cmEgbGEgZGlzY3JlcGFuemEgdHJhIGlsIG1vZGVsbG8gbnVsbCBlIGkgZGF0aSBvc3NlcnZhdGkuCgozLiAgKipSZXNpZHVhbCBEZXZpYW5jZSAoKiokRF97XHRleHR7cmVzaWR1YWx9fSQpOiBSYXBwcmVzZW50YSBsYSBkZXZpYW56YSByZXNpZHVhLCBjaW/DqCBsYSBkaXNjcmVwYW56YSBub24gc3BpZWdhdGEgZGFsIG1vZGVsbG8gZml0dGVkLgoKTCd1dGlsaXp6byBkaSBxdWVzdGUgY29tcG9uZW50aSBwZXJtZXR0ZSBkaSBjb21wcmVuZGVyZSBjb21lIGxhIGRldmlhbnphIMOoIGRpc3RyaWJ1aXRhIHRyYSBpbCBtb2RlbGxvIGZpdHRlZCwgaWwgbW9kZWxsbyBudWxsIGUgbGEgZGV2aWFuemEgcmVzaWR1YS4KCioqQ29uZnJvbnRvIHRyYSBNb2RlbGxpOioqIElsIHRlc3QgZGkgZGV2aWFuemEgw6ggc3Blc3NvIHV0aWxpenphdG8gcGVyIGNvbmZyb250YXJlIG1vZGVsbGkgYWx0ZXJuYXRpdmkuCkxhIGRpZmZlcmVuemEgbmVsbGEgZGV2aWFuemEgdHJhIGR1ZSBtb2RlbGxpIHNlZ3VlIGFwcHJvc3NpbWF0aXZhbWVudGUgdW5hIGRpc3RyaWJ1emlvbmUgY2hpLXF1YWRybyBzb3R0byBsJ2lwb3Rlc2kgbnVsbGEgY2hlIGkgZHVlIG1vZGVsbGkgc2lhbm8gZXF1aXZhbGVudGkuClF1ZXN0byB0ZXN0IHB1w7IgZXNzZXJlIHV0aWxpenphdG8gcGVyIHZhbHV0YXJlIGwnYWdnaXVudGEgZGkgcHJlZGl0dG9yaSBhbCBtb2RlbGxvIG8gcGVyIGNvbmZyb250YXJlIG1vZGVsbGkgY29uIGRpZmZlcmVudGkgc3BlY2lmaWNoZSBkaSBkaXN0cmlidXppb25lIGRlbGxhIHJpc3Bvc3RhLgoKKipFc2VtcGlvIGRpIERldmlhbnphOioqCgpgYGB7cn0KIyBDYXJpY2hpYW1vIHVuIGRhdGFzZXQgZGkgZXNlbXBpbyBpbiBSCmRhdGEobXRjYXJzKQoKIyBDcmVpYW1vIHVuIG1vZGVsbG8gZGkgUG9pc3Nvbgptb2RlbF9wb2lzc29uIDwtIGdsbSh2cyB+IHd0ICsgaHAsIGZhbWlseSA9IHBvaXNzb24sIGRhdGEgPSBtdGNhcnMpCgojIENhbGNvbGlhbW8gbGEgZGV2aWFuemEKZGV2aWFuY2VfdmFsdWUgPC0gZGV2aWFuY2UobW9kZWxfcG9pc3NvbikKCmNhdCgiRGV2aWFuemEgZGVsIE1vZGVsbG8gZGkgUG9pc3NvbjoiLCBkZXZpYW5jZV92YWx1ZSwgIlxuIikKCmBgYAoKSW4gcXVlc3RvIGVzZW1waW8sIGNhbGNvbGlhbW8gZSB2aXN1YWxpenppYW1vIGxhIGRldmlhbnphIHJlc2lkdWEgZGkgdW4gbW9kZWxsbyBkaSBQb2lzc29uLgoKIyMjIFJlc2lkdWkKCioqRnVuemlvbmUgZGVpIFJlc2lkdWkgbmVpIEdMTToqKiBOZWkgTW9kZWxsaSBMaW5lYXJpIEdlbmVyYWxpenphdGkgKEdMTSksIGkgcmVzaWR1aSBzdm9sZ29ubyB1biBydW9sbyBjcnVjaWFsZSBuZWwgdmFsdXRhcmUgbCdhZGF0dGFtZW50byBkZWwgbW9kZWxsbyBhaSBkYXRpIGUgbmVsIHZlcmlmaWNhcmUgbGEgdmFsaWRpdMOgIGRlbGxlIGlwb3Rlc2kgZGlldHJvIGlsIG1vZGVsbG8uCkEgZGlmZmVyZW56YSBkZWkgTW9kZWxsaSBMaW5lYXJpIChMTSksIGkgcmVzaWR1aSBuZWkgR0xNIHNvbm8gY2FsY29sYXRpIGNvbnNpZGVyYW5kbyBsYSBkaXN0cmlidXppb25lIGRlbGxhIHJpc3Bvc3RhIHNwZWNpZmljYSBkZWwgbW9kZWxsby4KCjEuICAqKk1pc3VyYXJlIGxhIEJvbnTDoCBkaSBBZGF0dGFtZW50bzoqKgogICAgLSAgIEkgcmVzaWR1aSBuZWkgR0xNIHNvbm8gdXRpbGl6emF0aSBwZXIgdmFsdXRhcmUgbGEgYm9udMOgIGRpIGFkYXR0YW1lbnRvIGRlbCBtb2RlbGxvLiBTZSBpbCBtb2RlbGxvIHNpIGFkYXR0YSBiZW5lIGFpIGRhdGksIGNpIHNpIGFzcGV0dGEgY2hlIGkgcmVzaWR1aSBhYmJpYW5vIHVuYSBkaXN0cmlidXppb25lIGNoZSByaWZsZXR0ZSBsYSBkaXN0cmlidXppb25lIGRlbGxhIHJpc3Bvc3RhIHNwZWNpZmljYXRhIG5lbCBHTE0uCjIuICAqKkluZGljYXppb25pIHN1bGxhIFN0cnV0dHVyYSBkZWkgRGF0aToqKgogICAgLSAgIE5laSBHTE0sIGxhIHNjZWx0YSBkZWxsYSBkaXN0cmlidXppb25lIGRlbGxhIHJpc3Bvc3RhIGUgZGVsbGEgZnVuemlvbmUgZGkgbGVnYW1lIHB1w7IgdmFyaWFyZSBpbiBiYXNlIGFsbGEgbmF0dXJhIGRlaSBkYXRpLiBJIHJlc2lkdWkgZm9ybmlzY29ubyBpbmRpY2F6aW9uaSBzdWxsYSBzdHJ1dHR1cmEgZGVpIGRhdGkgZSBzdWxsYSB2YWxpZGl0w6AgZGVsbGUgaXBvdGVzaSBkZWwgbW9kZWxsby4KMy4gICoqRGlhZ25vc3RpY2FyZSBEZXZpYW56YToqKgogICAgLSAgIExhIGRldmlhbnphLCB1bmEgbWlzdXJhIGRlbGxhIGRpZmZlcmVuemEgdHJhIGlsIG1vZGVsbG8gY29tcGxldG8gZSB1bm8gcGnDuSBzZW1wbGljZSwgcHXDsiBlc3NlcmUgZGlhZ25vc3RpY2F0YSBhdHRyYXZlcnNvIGkgcmVzaWR1aS4gUmVzaWR1aSBkZXZpYW50aSBlIHN0YW5kYXJkaXplZCBkZXZpYW5jZSByZXNpZHVhbHMgc29ubyBzcGVzc28gdXRpbGl6emF0aSBwZXIgaW5kaXZpZHVhcmUgbW9kZWxsaSBub24gYWRhdHRpIGFpIGRhdGkuCgoqKkRpZmZlcmVuemUgdHJhIFJlc2lkdWkgbmVpIEdMTSBlIG5laSBMTToqKiBMZSBwcmluY2lwYWxpIGRpZmZlcmVuemUgdHJhIGkgcmVzaWR1aSBuZWkgR0xNIGUgbmVpIExNIHJpZ3VhcmRhbm8gbGEgZGlzdHJpYnV6aW9uZSBkZWxsYSByaXNwb3N0YSBlIGxhIGZ1bnppb25lIGRpIGxlZ2FtZS4KCjEuICAqKkRpc3RyaWJ1emlvbmUgZGVsbGEgUmlzcG9zdGE6KioKICAgIC0gICBOZWkgR0xNLCBpIHJlc2lkdWkgc29ubyBjYWxjb2xhdGkgdGVuZW5kbyBjb250byBkZWxsYSBkaXN0cmlidXppb25lIGRlbGxhIHJpc3Bvc3RhIHNwZWNpZmljYXRhIG5lbCBtb2RlbGxvLiBBZCBlc2VtcGlvLCBuZWkgbW9kZWxsaSBkaSBQb2lzc29uLCBpIHJlc2lkdWkgZGV2b25vIGFkYXR0YXJzaSBhbGxhIGRpc3RyaWJ1emlvbmUgZGkgUG9pc3Nvbi4KICAgIC0gICBOZWkgTE0sIGkgcmVzaWR1aSBzb25vIGJhc2F0aSBzdWxsJ2Fzc3VuemlvbmUgY2hlIGxhIHJpc3Bvc3RhIHNpYSBkaXN0cmlidWl0YSBub3JtYWxtZW50ZS4KMi4gICoqRnVuemlvbmUgZGkgTGVnYW1lOioqCiAgICAtICAgTGEgZnVuemlvbmUgZGkgbGVnYW1lIG5laSBHTE0gZGV0ZXJtaW5hIGNvbWUgaWwgdmFsb3JlIGF0dGVzbyBkZWxsYSByaXNwb3N0YSDDqCBjb2xsZWdhdG8gYWxsYSBjb21iaW5hemlvbmUgbGluZWFyZSBkZWkgcHJlZGl0dG9yaS4gTGEgc2NlbHRhIGRlbGxhIGZ1bnppb25lIGRpIGxlZ2FtZSBpbmZsdWVuemEgaSByZXNpZHVpLgogICAgLSAgIE5laSBMTSwgbGEgZnVuemlvbmUgZGkgbGVnYW1lIMOoIGlkZW50aXTDoCwgZSBpIHJlc2lkdWkgcmlmbGV0dG9ubyBzZW1wbGljZW1lbnRlIGxhIGRpZmZlcmVuemEgdHJhIGkgdmFsb3JpIG9zc2VydmF0aSBlIHF1ZWxsaSBwcmV2aXN0aS4KCioqRXNlbXBpbyBkaSBDYWxjb2xvIGRlaSBSZXNpZHVpIGluIHVuIE1vZGVsbG8gR0xNOioqCgpgYGB7cn0Kc3VwcHJlc3NXYXJuaW5ncyh7CiMgQ2FyaWNoaWFtbyB1biBkYXRhc2V0IGRpIGVzZW1waW8gaW4gUiBjb24gdW5hIGRpc3RyaWJ1emlvbmUgZGkgUG9pc3NvbgpkYXRhKGZhaXRoZnVsLCBwYWNrYWdlID0gImRhdGFzZXRzIikKCiMgQ3JlaWFtbyB1biBtb2RlbGxvIGRpIFBvaXNzb24KbW9kZWxsb19wb2lzc29uIDwtIGdsbShlcnVwdGlvbnMgfiB3YWl0aW5nLCBmYW1pbHkgPSBwb2lzc29uLCBkYXRhID0gZmFpdGhmdWwpCgojIENhbGNvbGlhbW8gaSByZXNpZHVpIGRldmlhbnRpCnJlc2lkdWlfZGV2aWFudGkgPC0gcmVzaWR1YWxzKG1vZGVsbG9fcG9pc3NvbiwgdHlwZSA9ICJkZXZpYW5jZSIpCgojIFZpc3VhbGl6emlhbW8gaSBwcmltaSAxMCByZXNpZHVpIGRldmlhbnRpCmhlYWQocmVzaWR1aV9kZXZpYW50aSkKfSkKYGBgCgoqKkFuYWxpc2kgZGVpIFJlc2lkdWk6KiogSSByZXNpZHVpIGRldmlhbnRpIHJpZmxldHRvbm8gbGUgZGlmZmVyZW56ZSB0cmEgaSB2YWxvcmkgb3NzZXJ2YXRpIGUgcXVlbGxpIHByZXZpc3RpIGluIHRlcm1pbmkgZGVsbGEgZGV2aWFuemEgZGVsIG1vZGVsbG8uClVuIHJlc2lkdW8gZGV2aWFudGUgZWxldmF0byBpbmRpY2EgY2hlIGwnb3NzZXJ2YXppb25lIGNvbnRyaWJ1aXNjZSBpbiBtb2RvIHNpZ25pZmljYXRpdm8gYWxsYSBkZXZpYW56YSBjb21wbGVzc2l2YSBkZWwgbW9kZWxsbywgaW5kaWNhbmRvIHVuJ2V2ZW50dWFsZSBpbmZsdWVuemEgbyBkZXZpYXppb25lIGRhbCBtb2RlbGxvLgoKLSAgIFJlc2lkdWkgcG9zaXRpdmkgaW5kaWNhbm8gY2hlIGwnb3NzZXJ2YXppb25lIGhhIGNvbnRyaWJ1aXRvIHBpw7kgZGVsIHByZXZpc3RvIGFsbGEgZGV2aWFuemEuCi0gICBSZXNpZHVpIG5lZ2F0aXZpIGluZGljYW5vIGNoZSBsJ29zc2VydmF6aW9uZSBoYSBjb250cmlidWl0byBtZW5vIGRlbCBwcmV2aXN0byBhbGxhIGRldmlhbnphLgotICAgUmVzaWR1aSBwYXJpIGEgemVybyBpbmRpY2FubyB1bmEgcGVyZmV0dGEgYWRhdHRhYmlsaXTDoCBkZWxsJ29zc2VydmF6aW9uZSBhbCBtb2RlbGxvLgoKKipFc2VtcGlvKioKClBlciBxdWVzdG8gZXNlbXBpbywgdXNlcmVtbyBpbCBkYXRhc2V0IGRpIGVzZW1waW8gIm10Y2FycyIgZGkgUiBwZXIgY3JlYXJlIHVuIG1vZGVsbG8gZGkgUG9pc3NvbiB1dGlsaXp6YW5kbyB1biBtb2RlbGxvIGdlbmVyYWxpenphdG8gbGluZWFyZSAoR0xNKS4KTG8gc2NvcG8gZGVsIG1vZGVsbG8gc2Fyw6AgcHJldmVkZXJlIGlsIG51bWVybyBkaSBjaWxpbmRyaSAoImN5bCIpIGluIGJhc2UgYWxsZSBhbHRyZSB2YXJpYWJpbGkgcHJlc2VudGkgbmVsIGRhdGFzZXQuCgpgYGB7cn0KIyBDYXJpY2FtZW50byBkZWwgZGF0YXNldCAibXRjYXJzIgpkYXRhKG10Y2FycykKCiMgRXNwbG9yaWFtbyBsZSBwcmltZSByaWdoZSBkZWwgZGF0YXNldApoZWFkKG10Y2FycykKCiMgQ3JlaWFtbyB1biBtb2RlbGxvIGRpIFBvaXNzb24gcGVyIHByZXZlZGVyZSBpbCBudW1lcm8gZGkgY2lsaW5kcmkgaW4gYmFzZSBhbGxlIGFsdHJlIHZhcmlhYmlsaQptb2RlbGxvX2dsbSA8LSBnbG0oY3lsIH4gbXBnICsgZGlzcCArIGhwICsgZHJhdCArIHd0ICsgcXNlYyArIHZzICsgYW0gKyBnZWFyICsgY2FyYiwgCiAgICAgICAgICAgICAgICAgICBkYXRhID0gbXRjYXJzLCBmYW1pbHkgPSBwb2lzc29uKQoKIyBWaXN1YWxpenppYW1vIGlsIHN1bW1hcnkgZGVsIG1vZGVsbG8Kc3VtbWFyeShtb2RlbGxvX2dsbSkKCiMgQW5hbGl6emlhbW8gbGUgdmFyaWFiaWxpIGluZGlwZW5kZW50aQpwYXIobWZyb3cgPSBjKDIsIDIpKQpwbG90KG1vZGVsbG9fZ2xtKQoKIyBFc2VndWlhbW8gbCdhbmFsaXNpIGRlbGxhIHZhcmlhbnphIChBTk9WQSkKYW5vdmFfcmVzdWx0IDwtIGFub3ZhKG1vZGVsbG9fZ2xtLCB0ZXN0ID0gIkNoaSIpCgojIFZpc3VhbGl6emlhbW8gbGEgdGFiZWxsYSBBTk9WQQpwcmludChhbm92YV9yZXN1bHQpCgojIENhbGNvbGlhbW8gbCdSLXNxdWFyZWQgZGVsIG1vZGVsbG8Kcl9zcXVhcmVkIDwtIDEgLSAobW9kZWxsb19nbG0kZGV2aWFuY2UgLyBtb2RlbGxvX2dsbSRudWxsLmRldmlhbmNlKQpjYXQoIlItc3F1YXJlZDoiLCByX3NxdWFyZWQsICJcbiIpCgojIEVmZmV0dHVpYW1vIHByZXZpc2lvbmkgc3UgbnVvdmkgZGF0aSAocGVyIGVzZW1waW8sIGxlIHByaW1lIDUgb3NzZXJ2YXppb25pIGRlbCBkYXRhc2V0KQpudW92aV9kYXRpIDwtIG10Y2Fyc1sxOjUsIF0KcHJldmlzaW9uaSA8LSBwcmVkaWN0KG1vZGVsbG9fZ2xtLCBuZXdkYXRhID0gbnVvdmlfZGF0aSwgdHlwZSA9ICJyZXNwb25zZSIpCmNhdCgiUHJldmlzaW9uaSBwZXIgbGUgcHJpbWUgNSBvc3NlcnZhemlvbmk6XG4iLCBwcmV2aXNpb25pLCAiXG4iKQpgYGAKCkluIHF1ZXN0byBlc2VtcGlvLCBhYmJpYW1vIGNyZWF0byB1biBtb2RlbGxvIGRpIFBvaXNzb24gdXRpbGl6emFuZG8gaWwgbnVtZXJvIGRpIGNpbGluZHJpIGNvbWUgdmFyaWFiaWxlIGRpcGVuZGVudGUgZSBsZSBhbHRyZSB2YXJpYWJpbGkgZGVsIGRhdGFzZXQgIm10Y2FycyIgY29tZSB2YXJpYWJpbGkgaW5kaXBlbmRlbnRpLgpTdWNjZXNzaXZhbWVudGUsIGFiYmlhbW8gZXNlZ3VpdG8gdW4nYW5hbGlzaSBjb21wbGV0YSBkZWwgbW9kZWxsbywgY29tcHJlc2kgaWwgc3VtbWFyeSwgbGEgdmlzdWFsaXp6YXppb25lIGRlbGxlIHZhcmlhYmlsaSBpbmRpcGVuZGVudGksIGwnYW5hbGlzaSBkZWxsYSB2YXJpYW56YSAoQU5PVkEpLCBpbCBjYWxjb2xvIGRlbGwnUi1zcXVhcmVkIGUgbGEgcHJldmlzaW9uZSBzdSBudW92aSBkYXRpLgoKW1tUb3JuYSBhbGwnIFtJbmRpY2VdXV0K